Mercurial > hg > svgui
comparison view/Pane.cpp @ 127:89c625dda204
* Reorganising code base. This revision will not compile.
author | Chris Cannam |
---|---|
date | Mon, 31 Jul 2006 11:44:37 +0000 |
parents | |
children | 33929e0c3c6b |
comparison
equal
deleted
inserted
replaced
126:0e95c127bb53 | 127:89c625dda204 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006 Chris Cannam. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "widgets/Pane.h" | |
17 #include "base/Layer.h" | |
18 #include "base/Model.h" | |
19 #include "base/ZoomConstraint.h" | |
20 #include "base/RealTime.h" | |
21 #include "base/Profiler.h" | |
22 #include "base/ViewManager.h" | |
23 #include "base/CommandHistory.h" | |
24 #include "layer/WaveformLayer.h" | |
25 | |
26 #include <QPaintEvent> | |
27 #include <QPainter> | |
28 #include <iostream> | |
29 #include <cmath> | |
30 | |
31 using std::cerr; | |
32 using std::endl; | |
33 | |
34 Pane::Pane(QWidget *w) : | |
35 View(w, true), | |
36 m_identifyFeatures(false), | |
37 m_clickedInRange(false), | |
38 m_shiftPressed(false), | |
39 m_ctrlPressed(false), | |
40 m_navigating(false), | |
41 m_resizing(false), | |
42 m_centreLineVisible(true) | |
43 { | |
44 setObjectName("Pane"); | |
45 setMouseTracking(true); | |
46 } | |
47 | |
48 bool | |
49 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const | |
50 { | |
51 QPoint discard; | |
52 bool b0, b1; | |
53 | |
54 if (layer == getSelectedLayer() && | |
55 !shouldIlluminateLocalSelection(discard, b0, b1)) { | |
56 | |
57 pos = m_identifyPoint; | |
58 return m_identifyFeatures; | |
59 } | |
60 | |
61 return false; | |
62 } | |
63 | |
64 bool | |
65 Pane::shouldIlluminateLocalSelection(QPoint &pos, | |
66 bool &closeToLeft, | |
67 bool &closeToRight) const | |
68 { | |
69 if (m_identifyFeatures && | |
70 m_manager && | |
71 m_manager->getToolMode() == ViewManager::EditMode && | |
72 !m_manager->getSelections().empty() && | |
73 !selectionIsBeingEdited()) { | |
74 | |
75 Selection s(getSelectionAt(m_identifyPoint.x(), | |
76 closeToLeft, closeToRight)); | |
77 | |
78 if (!s.isEmpty()) { | |
79 if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) { | |
80 | |
81 pos = m_identifyPoint; | |
82 return true; | |
83 } | |
84 } | |
85 } | |
86 | |
87 return false; | |
88 } | |
89 | |
90 bool | |
91 Pane::selectionIsBeingEdited() const | |
92 { | |
93 if (!m_editingSelection.isEmpty()) { | |
94 if (m_mousePos != m_clickPos && | |
95 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) { | |
96 return true; | |
97 } | |
98 } | |
99 return false; | |
100 } | |
101 | |
102 void | |
103 Pane::setCentreLineVisible(bool visible) | |
104 { | |
105 m_centreLineVisible = visible; | |
106 update(); | |
107 } | |
108 | |
109 void | |
110 Pane::paintEvent(QPaintEvent *e) | |
111 { | |
112 // Profiler profiler("Pane::paintEvent", true); | |
113 | |
114 QPainter paint; | |
115 | |
116 QRect r(rect()); | |
117 | |
118 if (e) { | |
119 r = e->rect(); | |
120 } | |
121 /* | |
122 paint.begin(this); | |
123 paint.setClipRect(r); | |
124 | |
125 if (hasLightBackground()) { | |
126 paint.setPen(Qt::white); | |
127 paint.setBrush(Qt::white); | |
128 } else { | |
129 paint.setPen(Qt::black); | |
130 paint.setBrush(Qt::black); | |
131 } | |
132 paint.drawRect(r); | |
133 | |
134 paint.end(); | |
135 */ | |
136 View::paintEvent(e); | |
137 | |
138 paint.begin(this); | |
139 | |
140 if (e) { | |
141 paint.setClipRect(r); | |
142 } | |
143 | |
144 const Model *waveformModel = 0; // just for reporting purposes | |
145 int verticalScaleWidth = 0; | |
146 | |
147 int fontHeight = paint.fontMetrics().height(); | |
148 int fontAscent = paint.fontMetrics().ascent(); | |
149 | |
150 if (m_manager && | |
151 !m_manager->isPlaying() && | |
152 m_manager->getToolMode() == ViewManager::SelectMode) { | |
153 | |
154 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) { | |
155 --vi; | |
156 | |
157 std::vector<QRect> crosshairExtents; | |
158 | |
159 if ((*vi)->getCrosshairExtents(this, paint, m_identifyPoint, | |
160 crosshairExtents)) { | |
161 (*vi)->paintCrosshairs(this, paint, m_identifyPoint); | |
162 break; | |
163 } else if ((*vi)->isLayerOpaque()) { | |
164 break; | |
165 } | |
166 } | |
167 } | |
168 | |
169 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) { | |
170 --vi; | |
171 | |
172 if (dynamic_cast<WaveformLayer *>(*vi)) { | |
173 waveformModel = (*vi)->getModel(); | |
174 } | |
175 | |
176 if (!m_manager || | |
177 m_manager->getOverlayMode() == ViewManager::NoOverlays) { | |
178 break; | |
179 } | |
180 | |
181 verticalScaleWidth = (*vi)->getVerticalScaleWidth(this, paint); | |
182 | |
183 if (verticalScaleWidth > 0 && r.left() < verticalScaleWidth) { | |
184 | |
185 // Profiler profiler("Pane::paintEvent - painting vertical scale", true); | |
186 | |
187 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl; | |
188 paint.save(); | |
189 | |
190 paint.setPen(Qt::black); | |
191 paint.setBrush(Qt::white); | |
192 paint.drawRect(0, -1, verticalScaleWidth, height()+1); | |
193 | |
194 paint.setBrush(Qt::NoBrush); | |
195 (*vi)->paintVerticalScale | |
196 (this, paint, QRect(0, 0, verticalScaleWidth, height())); | |
197 | |
198 paint.restore(); | |
199 } | |
200 | |
201 if (m_identifyFeatures) { | |
202 | |
203 QPoint pos = m_identifyPoint; | |
204 QString desc = (*vi)->getFeatureDescription(this, pos); | |
205 | |
206 if (desc != "") { | |
207 | |
208 paint.save(); | |
209 | |
210 int tabStop = | |
211 paint.fontMetrics().width(tr("Some lengthy prefix:")); | |
212 | |
213 QRect boundingRect = | |
214 paint.fontMetrics().boundingRect | |
215 (rect(), | |
216 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs, | |
217 desc, tabStop); | |
218 | |
219 if (hasLightBackground()) { | |
220 paint.setPen(Qt::NoPen); | |
221 paint.setBrush(QColor(250, 250, 250, 200)); | |
222 } else { | |
223 paint.setPen(Qt::NoPen); | |
224 paint.setBrush(QColor(50, 50, 50, 200)); | |
225 } | |
226 | |
227 int extra = paint.fontMetrics().descent(); | |
228 paint.drawRect(width() - boundingRect.width() - 10 - extra, | |
229 10 - extra, | |
230 boundingRect.width() + 2 * extra, | |
231 boundingRect.height() + extra); | |
232 | |
233 if (hasLightBackground()) { | |
234 paint.setPen(QColor(150, 20, 0)); | |
235 } else { | |
236 paint.setPen(QColor(255, 150, 100)); | |
237 } | |
238 | |
239 QTextOption option; | |
240 option.setWrapMode(QTextOption::NoWrap); | |
241 option.setAlignment(Qt::AlignRight | Qt::AlignTop); | |
242 option.setTabStop(tabStop); | |
243 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10, | |
244 boundingRect.width(), | |
245 boundingRect.height()), | |
246 desc, | |
247 option); | |
248 | |
249 paint.restore(); | |
250 } | |
251 } | |
252 | |
253 break; | |
254 } | |
255 | |
256 int sampleRate = getModelsSampleRate(); | |
257 paint.setBrush(Qt::NoBrush); | |
258 | |
259 if (m_centreLineVisible) { | |
260 | |
261 if (hasLightBackground()) { | |
262 paint.setPen(QColor(50, 50, 50)); | |
263 } else { | |
264 paint.setPen(QColor(200, 200, 200)); | |
265 } | |
266 paint.drawLine(width() / 2, 0, width() / 2, height() - 1); | |
267 | |
268 paint.setPen(QColor(50, 50, 50)); | |
269 | |
270 int y = height() - fontHeight | |
271 + fontAscent - 6; | |
272 | |
273 LayerList::iterator vi = m_layers.end(); | |
274 | |
275 if (vi != m_layers.begin()) { | |
276 | |
277 switch ((*--vi)->getPreferredFrameCountPosition()) { | |
278 | |
279 case Layer::PositionTop: | |
280 y = fontAscent + 6; | |
281 break; | |
282 | |
283 case Layer::PositionMiddle: | |
284 y = (height() - fontHeight) / 2 | |
285 + fontAscent; | |
286 break; | |
287 | |
288 case Layer::PositionBottom: | |
289 // y already set correctly | |
290 break; | |
291 } | |
292 } | |
293 | |
294 if (m_manager && | |
295 m_manager->getOverlayMode() != ViewManager::NoOverlays) { | |
296 | |
297 if (sampleRate) { | |
298 | |
299 QString text(QString::fromStdString | |
300 (RealTime::frame2RealTime | |
301 (m_centreFrame, sampleRate).toText(true))); | |
302 | |
303 int tw = paint.fontMetrics().width(text); | |
304 int x = width()/2 - 4 - tw; | |
305 | |
306 drawVisibleText(paint, x, y, text, OutlinedText); | |
307 } | |
308 | |
309 QString text = QString("%1").arg(m_centreFrame); | |
310 | |
311 int tw = paint.fontMetrics().width(text); | |
312 int x = width()/2 + 4; | |
313 | |
314 drawVisibleText(paint, x, y, text, OutlinedText); | |
315 } | |
316 | |
317 } else { | |
318 | |
319 paint.setPen(QColor(50, 50, 50)); | |
320 } | |
321 | |
322 if (waveformModel && | |
323 m_manager && | |
324 m_manager->getOverlayMode() != ViewManager::NoOverlays && | |
325 r.y() + r.height() >= height() - fontHeight - 6) { | |
326 | |
327 size_t mainModelRate = m_manager->getMainModelSampleRate(); | |
328 size_t playbackRate = m_manager->getPlaybackSampleRate(); | |
329 | |
330 QString srNote = ""; | |
331 | |
332 // Show (R) for waveform models that will be resampled on | |
333 // playback, and (X) for waveform models that will be played | |
334 // at the wrong rate because their rate differs from that of | |
335 // the main model. | |
336 | |
337 if (sampleRate == mainModelRate) { | |
338 if (sampleRate != playbackRate) srNote = " " + tr("(R)"); | |
339 } else { | |
340 std::cerr << "Sample rate = " << sampleRate << ", main model rate = " << mainModelRate << std::endl; | |
341 srNote = " " + tr("(X)"); | |
342 } | |
343 | |
344 QString desc = tr("%1 / %2Hz%3") | |
345 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(), | |
346 sampleRate) | |
347 .toText(false).c_str()) | |
348 .arg(sampleRate) | |
349 .arg(srNote); | |
350 | |
351 if (r.x() < verticalScaleWidth + 5 + paint.fontMetrics().width(desc)) { | |
352 drawVisibleText(paint, verticalScaleWidth + 5, | |
353 height() - fontHeight + fontAscent - 6, | |
354 desc, OutlinedText); | |
355 } | |
356 } | |
357 | |
358 if (m_manager && | |
359 m_manager->getOverlayMode() == ViewManager::AllOverlays && | |
360 r.y() + r.height() >= height() - m_layers.size() * fontHeight - 6) { | |
361 | |
362 std::vector<QString> texts; | |
363 int maxTextWidth = 0; | |
364 | |
365 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
366 | |
367 QString text = (*i)->getLayerPresentationName(); | |
368 int tw = paint.fontMetrics().width(text); | |
369 bool reduced = false; | |
370 while (tw > width() / 3 && text.length() > 4) { | |
371 if (!reduced && text.length() > 8) { | |
372 text = text.left(text.length() - 4); | |
373 } else { | |
374 text = text.left(text.length() - 2); | |
375 } | |
376 reduced = true; | |
377 tw = paint.fontMetrics().width(text + "..."); | |
378 } | |
379 if (reduced) { | |
380 texts.push_back(text + "..."); | |
381 } else { | |
382 texts.push_back(text); | |
383 } | |
384 if (tw > maxTextWidth) maxTextWidth = tw; | |
385 } | |
386 | |
387 int lly = height() - 6; | |
388 | |
389 if (r.x() + r.width() >= width() - maxTextWidth - 5) { | |
390 | |
391 for (int i = 0; i < texts.size(); ++i) { | |
392 | |
393 if (i == texts.size() - 1) { | |
394 paint.setPen(Qt::black); | |
395 } | |
396 | |
397 drawVisibleText(paint, width() - maxTextWidth - 5, | |
398 lly - fontHeight + fontAscent, | |
399 texts[i], OutlinedText); | |
400 | |
401 lly -= fontHeight; | |
402 } | |
403 } | |
404 } | |
405 | |
406 if (m_clickedInRange && m_shiftPressed) { | |
407 if (m_manager && (m_manager->getToolMode() == ViewManager::NavigateMode)) { | |
408 //!!! be nice if this looked a bit more in keeping with the | |
409 //selection block | |
410 paint.setPen(Qt::blue); | |
411 paint.drawRect(m_clickPos.x(), m_clickPos.y(), | |
412 m_mousePos.x() - m_clickPos.x(), | |
413 m_mousePos.y() - m_clickPos.y()); | |
414 } | |
415 } | |
416 | |
417 if (selectionIsBeingEdited()) { | |
418 | |
419 int offset = m_mousePos.x() - m_clickPos.x(); | |
420 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset; | |
421 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset; | |
422 | |
423 if (m_editingSelectionEdge < 0) { | |
424 p1 = getXForFrame(m_editingSelection.getEndFrame()); | |
425 } else if (m_editingSelectionEdge > 0) { | |
426 p0 = getXForFrame(m_editingSelection.getStartFrame()); | |
427 } | |
428 | |
429 paint.save(); | |
430 if (hasLightBackground()) { | |
431 paint.setPen(QPen(Qt::black, 2)); | |
432 } else { | |
433 paint.setPen(QPen(Qt::white, 2)); | |
434 } | |
435 | |
436 //!!! duplicating display policy with View::drawSelections | |
437 | |
438 if (m_editingSelectionEdge < 0) { | |
439 paint.drawLine(p0, 1, p1, 1); | |
440 paint.drawLine(p0, 0, p0, height()); | |
441 paint.drawLine(p0, height() - 1, p1, height() - 1); | |
442 } else if (m_editingSelectionEdge > 0) { | |
443 paint.drawLine(p0, 1, p1, 1); | |
444 paint.drawLine(p1, 0, p1, height()); | |
445 paint.drawLine(p0, height() - 1, p1, height() - 1); | |
446 } else { | |
447 paint.setBrush(Qt::NoBrush); | |
448 paint.drawRect(p0, 1, p1 - p0, height() - 2); | |
449 } | |
450 paint.restore(); | |
451 } | |
452 | |
453 paint.end(); | |
454 } | |
455 | |
456 Selection | |
457 Pane::getSelectionAt(int x, bool &closeToLeftEdge, bool &closeToRightEdge) const | |
458 { | |
459 closeToLeftEdge = closeToRightEdge = false; | |
460 | |
461 if (!m_manager) return Selection(); | |
462 | |
463 long testFrame = getFrameForX(x - 5); | |
464 if (testFrame < 0) { | |
465 testFrame = getFrameForX(x); | |
466 if (testFrame < 0) return Selection(); | |
467 } | |
468 | |
469 Selection selection = m_manager->getContainingSelection(testFrame, true); | |
470 if (selection.isEmpty()) return selection; | |
471 | |
472 int lx = getXForFrame(selection.getStartFrame()); | |
473 int rx = getXForFrame(selection.getEndFrame()); | |
474 | |
475 int fuzz = 2; | |
476 if (x < lx - fuzz || x > rx + fuzz) return Selection(); | |
477 | |
478 int width = rx - lx; | |
479 fuzz = 3; | |
480 if (width < 12) fuzz = width / 4; | |
481 if (fuzz < 1) fuzz = 1; | |
482 | |
483 if (x < lx + fuzz) closeToLeftEdge = true; | |
484 if (x > rx - fuzz) closeToRightEdge = true; | |
485 | |
486 return selection; | |
487 } | |
488 | |
489 void | |
490 Pane::mousePressEvent(QMouseEvent *e) | |
491 { | |
492 if (e->buttons() & Qt::RightButton) { | |
493 emit rightButtonMenuRequested(mapToGlobal(e->pos())); | |
494 return; | |
495 } | |
496 | |
497 m_clickPos = e->pos(); | |
498 m_clickedInRange = true; | |
499 m_editingSelection = Selection(); | |
500 m_editingSelectionEdge = 0; | |
501 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier); | |
502 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier); | |
503 | |
504 ViewManager::ToolMode mode = ViewManager::NavigateMode; | |
505 if (m_manager) mode = m_manager->getToolMode(); | |
506 | |
507 m_navigating = false; | |
508 | |
509 if (mode == ViewManager::NavigateMode || (e->buttons() & Qt::MidButton)) { | |
510 | |
511 if (mode != ViewManager::NavigateMode) { | |
512 setCursor(Qt::PointingHandCursor); | |
513 } | |
514 | |
515 m_navigating = true; | |
516 m_dragCentreFrame = m_centreFrame; | |
517 | |
518 } else if (mode == ViewManager::SelectMode) { | |
519 | |
520 bool closeToLeft = false, closeToRight = false; | |
521 Selection selection = getSelectionAt(e->x(), closeToLeft, closeToRight); | |
522 | |
523 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) { | |
524 | |
525 m_manager->removeSelection(selection); | |
526 | |
527 if (closeToLeft) { | |
528 m_selectionStartFrame = selection.getEndFrame(); | |
529 } else { | |
530 m_selectionStartFrame = selection.getStartFrame(); | |
531 } | |
532 | |
533 m_manager->setInProgressSelection(selection, false); | |
534 m_resizing = true; | |
535 | |
536 } else { | |
537 | |
538 int mouseFrame = getFrameForX(e->x()); | |
539 size_t resolution = 1; | |
540 int snapFrame = mouseFrame; | |
541 | |
542 Layer *layer = getSelectedLayer(); | |
543 if (layer && !m_shiftPressed) { | |
544 layer->snapToFeatureFrame(this, snapFrame, | |
545 resolution, Layer::SnapLeft); | |
546 } | |
547 | |
548 if (snapFrame < 0) snapFrame = 0; | |
549 m_selectionStartFrame = snapFrame; | |
550 if (m_manager) { | |
551 m_manager->setInProgressSelection(Selection(snapFrame, | |
552 snapFrame + resolution), | |
553 !m_ctrlPressed); | |
554 } | |
555 | |
556 m_resizing = false; | |
557 } | |
558 | |
559 update(); | |
560 | |
561 } else if (mode == ViewManager::DrawMode) { | |
562 | |
563 Layer *layer = getSelectedLayer(); | |
564 if (layer && layer->isLayerEditable()) { | |
565 layer->drawStart(this, e); | |
566 } | |
567 | |
568 } else if (mode == ViewManager::EditMode) { | |
569 | |
570 if (!editSelectionStart(e)) { | |
571 Layer *layer = getSelectedLayer(); | |
572 if (layer && layer->isLayerEditable()) { | |
573 layer->editStart(this, e); | |
574 } | |
575 } | |
576 } | |
577 | |
578 emit paneInteractedWith(); | |
579 } | |
580 | |
581 void | |
582 Pane::mouseReleaseEvent(QMouseEvent *e) | |
583 { | |
584 if (e->buttons() & Qt::RightButton) { | |
585 return; | |
586 } | |
587 | |
588 ViewManager::ToolMode mode = ViewManager::NavigateMode; | |
589 if (m_manager) mode = m_manager->getToolMode(); | |
590 | |
591 if (m_clickedInRange) { | |
592 mouseMoveEvent(e); | |
593 } | |
594 | |
595 if (m_navigating || mode == ViewManager::NavigateMode) { | |
596 | |
597 m_navigating = false; | |
598 | |
599 if (mode != ViewManager::NavigateMode) { | |
600 // restore cursor | |
601 toolModeChanged(); | |
602 } | |
603 | |
604 if (m_shiftPressed) { | |
605 | |
606 int x0 = std::min(m_clickPos.x(), m_mousePos.x()); | |
607 int x1 = std::max(m_clickPos.x(), m_mousePos.x()); | |
608 int w = x1 - x0; | |
609 | |
610 int y0 = std::min(m_clickPos.y(), m_mousePos.y()); | |
611 int y1 = std::max(m_clickPos.y(), m_mousePos.y()); | |
612 // int h = y1 - y0; | |
613 | |
614 long newStartFrame = getFrameForX(x0); | |
615 | |
616 long visibleFrames = getEndFrame() - getStartFrame(); | |
617 if (newStartFrame <= -visibleFrames) { | |
618 newStartFrame = -visibleFrames + 1; | |
619 } | |
620 | |
621 if (newStartFrame >= long(getModelsEndFrame())) { | |
622 newStartFrame = getModelsEndFrame() - 1; | |
623 } | |
624 | |
625 float ratio = float(w) / float(width()); | |
626 // std::cerr << "ratio: " << ratio << std::endl; | |
627 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio); | |
628 if (newZoomLevel < 1) newZoomLevel = 1; | |
629 | |
630 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl; | |
631 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel)); | |
632 setStartFrame(newStartFrame); | |
633 | |
634 //!!! lots of faff, shouldn't be here | |
635 | |
636 QString unit; | |
637 float min, max; | |
638 bool log; | |
639 Layer *layer = 0; | |
640 for (LayerList::const_iterator i = m_layers.begin(); | |
641 i != m_layers.end(); ++i) { | |
642 if ((*i)->getValueExtents(min, max, log, unit) && | |
643 (*i)->getDisplayExtents(min, max)) { | |
644 layer = *i; | |
645 break; | |
646 } | |
647 } | |
648 | |
649 if (layer) { | |
650 if (log) { | |
651 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min); | |
652 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max); | |
653 } | |
654 float rmin = min + ((max - min) * (height() - y1)) / height(); | |
655 float rmax = min + ((max - min) * (height() - y0)) / height(); | |
656 std::cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << std::endl; | |
657 if (log) { | |
658 rmin = powf(10, rmin); | |
659 rmax = powf(10, rmax); | |
660 } | |
661 std::cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit.toStdString() << std::endl; | |
662 | |
663 layer->setDisplayExtents(rmin, rmax); | |
664 } | |
665 | |
666 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl; | |
667 // update(); | |
668 } | |
669 | |
670 } else if (mode == ViewManager::SelectMode) { | |
671 | |
672 if (m_manager && m_manager->haveInProgressSelection()) { | |
673 | |
674 bool exclusive; | |
675 Selection selection = m_manager->getInProgressSelection(exclusive); | |
676 | |
677 if (selection.getEndFrame() < selection.getStartFrame() + 2) { | |
678 selection = Selection(); | |
679 } | |
680 | |
681 m_manager->clearInProgressSelection(); | |
682 | |
683 if (exclusive) { | |
684 m_manager->setSelection(selection); | |
685 } else { | |
686 m_manager->addSelection(selection); | |
687 } | |
688 } | |
689 | |
690 update(); | |
691 | |
692 } else if (mode == ViewManager::DrawMode) { | |
693 | |
694 Layer *layer = getSelectedLayer(); | |
695 if (layer && layer->isLayerEditable()) { | |
696 layer->drawEnd(this, e); | |
697 update(); | |
698 } | |
699 | |
700 } else if (mode == ViewManager::EditMode) { | |
701 | |
702 if (!editSelectionEnd(e)) { | |
703 Layer *layer = getSelectedLayer(); | |
704 if (layer && layer->isLayerEditable()) { | |
705 layer->editEnd(this, e); | |
706 update(); | |
707 } | |
708 } | |
709 } | |
710 | |
711 m_clickedInRange = false; | |
712 | |
713 emit paneInteractedWith(); | |
714 } | |
715 | |
716 void | |
717 Pane::mouseMoveEvent(QMouseEvent *e) | |
718 { | |
719 if (e->buttons() & Qt::RightButton) { | |
720 return; | |
721 } | |
722 | |
723 ViewManager::ToolMode mode = ViewManager::NavigateMode; | |
724 if (m_manager) mode = m_manager->getToolMode(); | |
725 | |
726 QPoint prevPoint = m_identifyPoint; | |
727 m_identifyPoint = e->pos(); | |
728 | |
729 if (!m_clickedInRange) { | |
730 | |
731 if (mode == ViewManager::SelectMode) { | |
732 bool closeToLeft = false, closeToRight = false; | |
733 getSelectionAt(e->x(), closeToLeft, closeToRight); | |
734 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) { | |
735 setCursor(Qt::SizeHorCursor); | |
736 } else { | |
737 setCursor(Qt::ArrowCursor); | |
738 } | |
739 } | |
740 | |
741 //!!! if (mode != ViewManager::DrawMode) { | |
742 | |
743 if (!m_manager->isPlaying()) { | |
744 | |
745 if (getSelectedLayer()) { | |
746 | |
747 bool previouslyIdentifying = m_identifyFeatures; | |
748 m_identifyFeatures = true; | |
749 | |
750 if (m_identifyFeatures != previouslyIdentifying || | |
751 m_identifyPoint != prevPoint) { | |
752 update(); | |
753 } | |
754 } | |
755 | |
756 } | |
757 | |
758 // } | |
759 | |
760 return; | |
761 } | |
762 | |
763 if (m_navigating || mode == ViewManager::NavigateMode) { | |
764 | |
765 if (m_shiftPressed) { | |
766 | |
767 m_mousePos = e->pos(); | |
768 update(); | |
769 | |
770 } else { | |
771 | |
772 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x()); | |
773 | |
774 size_t newCentreFrame = m_dragCentreFrame; | |
775 | |
776 if (frameOff < 0) { | |
777 newCentreFrame -= frameOff; | |
778 } else if (newCentreFrame >= size_t(frameOff)) { | |
779 newCentreFrame -= frameOff; | |
780 } else { | |
781 newCentreFrame = 0; | |
782 } | |
783 | |
784 if (newCentreFrame >= getModelsEndFrame()) { | |
785 newCentreFrame = getModelsEndFrame(); | |
786 if (newCentreFrame > 0) --newCentreFrame; | |
787 } | |
788 | |
789 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) { | |
790 setCentreFrame(newCentreFrame); | |
791 } | |
792 } | |
793 | |
794 } else if (mode == ViewManager::SelectMode) { | |
795 | |
796 int mouseFrame = getFrameForX(e->x()); | |
797 size_t resolution = 1; | |
798 int snapFrameLeft = mouseFrame; | |
799 int snapFrameRight = mouseFrame; | |
800 | |
801 Layer *layer = getSelectedLayer(); | |
802 if (layer && !m_shiftPressed) { | |
803 layer->snapToFeatureFrame(this, snapFrameLeft, | |
804 resolution, Layer::SnapLeft); | |
805 layer->snapToFeatureFrame(this, snapFrameRight, | |
806 resolution, Layer::SnapRight); | |
807 } | |
808 | |
809 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl; | |
810 | |
811 if (snapFrameLeft < 0) snapFrameLeft = 0; | |
812 if (snapFrameRight < 0) snapFrameRight = 0; | |
813 | |
814 size_t min, max; | |
815 | |
816 if (m_selectionStartFrame > snapFrameLeft) { | |
817 min = snapFrameLeft; | |
818 max = m_selectionStartFrame; | |
819 } else if (snapFrameRight > m_selectionStartFrame) { | |
820 min = m_selectionStartFrame; | |
821 max = snapFrameRight; | |
822 } else { | |
823 min = snapFrameLeft; | |
824 max = snapFrameRight; | |
825 } | |
826 | |
827 if (m_manager) { | |
828 m_manager->setInProgressSelection(Selection(min, max), | |
829 !m_resizing && !m_ctrlPressed); | |
830 } | |
831 | |
832 bool doScroll = false; | |
833 if (!m_manager) doScroll = true; | |
834 if (!m_manager->isPlaying()) doScroll = true; | |
835 if (m_followPlay != PlaybackScrollContinuous) doScroll = true; | |
836 | |
837 if (doScroll) { | |
838 int offset = mouseFrame - getStartFrame(); | |
839 int available = getEndFrame() - getStartFrame(); | |
840 if (offset >= available * 0.95) { | |
841 int move = int(offset - available * 0.95) + 1; | |
842 setCentreFrame(m_centreFrame + move); | |
843 } else if (offset <= available * 0.10) { | |
844 int move = int(available * 0.10 - offset) + 1; | |
845 if (m_centreFrame > move) { | |
846 setCentreFrame(m_centreFrame - move); | |
847 } else { | |
848 setCentreFrame(0); | |
849 } | |
850 } | |
851 } | |
852 | |
853 update(); | |
854 | |
855 } else if (mode == ViewManager::DrawMode) { | |
856 | |
857 Layer *layer = getSelectedLayer(); | |
858 if (layer && layer->isLayerEditable()) { | |
859 layer->drawDrag(this, e); | |
860 } | |
861 | |
862 } else if (mode == ViewManager::EditMode) { | |
863 | |
864 if (!editSelectionDrag(e)) { | |
865 Layer *layer = getSelectedLayer(); | |
866 if (layer && layer->isLayerEditable()) { | |
867 layer->editDrag(this, e); | |
868 } | |
869 } | |
870 } | |
871 } | |
872 | |
873 void | |
874 Pane::mouseDoubleClickEvent(QMouseEvent *e) | |
875 { | |
876 if (e->buttons() & Qt::RightButton) { | |
877 return; | |
878 } | |
879 | |
880 // std::cerr << "mouseDoubleClickEvent" << std::endl; | |
881 | |
882 m_clickPos = e->pos(); | |
883 m_clickedInRange = true; | |
884 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier); | |
885 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier); | |
886 | |
887 ViewManager::ToolMode mode = ViewManager::NavigateMode; | |
888 if (m_manager) mode = m_manager->getToolMode(); | |
889 | |
890 if (mode == ViewManager::NavigateMode || | |
891 mode == ViewManager::EditMode) { | |
892 | |
893 Layer *layer = getSelectedLayer(); | |
894 if (layer && layer->isLayerEditable()) { | |
895 layer->editOpen(this, e); | |
896 } | |
897 } | |
898 } | |
899 | |
900 void | |
901 Pane::leaveEvent(QEvent *) | |
902 { | |
903 bool previouslyIdentifying = m_identifyFeatures; | |
904 m_identifyFeatures = false; | |
905 if (previouslyIdentifying) update(); | |
906 } | |
907 | |
908 void | |
909 Pane::wheelEvent(QWheelEvent *e) | |
910 { | |
911 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl; | |
912 | |
913 int count = e->delta(); | |
914 | |
915 if (count > 0) { | |
916 if (count >= 120) count /= 120; | |
917 else count = 1; | |
918 } | |
919 | |
920 if (count < 0) { | |
921 if (count <= -120) count /= 120; | |
922 else count = -1; | |
923 } | |
924 | |
925 if (e->modifiers() & Qt::ControlModifier) { | |
926 | |
927 // Scroll left or right, rapidly | |
928 | |
929 if (getStartFrame() < 0 && | |
930 getEndFrame() >= getModelsEndFrame()) return; | |
931 | |
932 long delta = ((width() / 2) * count * m_zoomLevel); | |
933 | |
934 if (int(m_centreFrame) < delta) { | |
935 setCentreFrame(0); | |
936 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) { | |
937 setCentreFrame(getModelsEndFrame()); | |
938 } else { | |
939 setCentreFrame(m_centreFrame - delta); | |
940 } | |
941 | |
942 } else { | |
943 | |
944 // Zoom in or out | |
945 | |
946 int newZoomLevel = m_zoomLevel; | |
947 | |
948 while (count > 0) { | |
949 if (newZoomLevel <= 2) { | |
950 newZoomLevel = 1; | |
951 break; | |
952 } | |
953 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1, | |
954 ZoomConstraint::RoundDown); | |
955 --count; | |
956 } | |
957 | |
958 while (count < 0) { | |
959 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1, | |
960 ZoomConstraint::RoundUp); | |
961 ++count; | |
962 } | |
963 | |
964 if (newZoomLevel != m_zoomLevel) { | |
965 setZoomLevel(newZoomLevel); | |
966 } | |
967 } | |
968 | |
969 emit paneInteractedWith(); | |
970 } | |
971 | |
972 bool | |
973 Pane::editSelectionStart(QMouseEvent *e) | |
974 { | |
975 if (!m_identifyFeatures || | |
976 !m_manager || | |
977 m_manager->getToolMode() != ViewManager::EditMode) { | |
978 return false; | |
979 } | |
980 | |
981 bool closeToLeft, closeToRight; | |
982 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight)); | |
983 if (s.isEmpty()) return false; | |
984 m_editingSelection = s; | |
985 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0); | |
986 m_mousePos = e->pos(); | |
987 return true; | |
988 } | |
989 | |
990 bool | |
991 Pane::editSelectionDrag(QMouseEvent *e) | |
992 { | |
993 if (m_editingSelection.isEmpty()) return false; | |
994 m_mousePos = e->pos(); | |
995 update(); | |
996 return true; | |
997 } | |
998 | |
999 bool | |
1000 Pane::editSelectionEnd(QMouseEvent *e) | |
1001 { | |
1002 if (m_editingSelection.isEmpty()) return false; | |
1003 | |
1004 int offset = m_mousePos.x() - m_clickPos.x(); | |
1005 Layer *layer = getSelectedLayer(); | |
1006 | |
1007 if (offset == 0 || !layer) { | |
1008 m_editingSelection = Selection(); | |
1009 return true; | |
1010 } | |
1011 | |
1012 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset; | |
1013 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset; | |
1014 | |
1015 long f0 = getFrameForX(p0); | |
1016 long f1 = getFrameForX(p1); | |
1017 | |
1018 Selection newSelection(f0, f1); | |
1019 | |
1020 if (m_editingSelectionEdge == 0) { | |
1021 | |
1022 CommandHistory::getInstance()->startCompoundOperation | |
1023 (tr("Drag Selection"), true); | |
1024 | |
1025 layer->moveSelection(m_editingSelection, f0); | |
1026 | |
1027 } else { | |
1028 | |
1029 CommandHistory::getInstance()->startCompoundOperation | |
1030 (tr("Resize Selection"), true); | |
1031 | |
1032 if (m_editingSelectionEdge < 0) { | |
1033 f1 = m_editingSelection.getEndFrame(); | |
1034 } else { | |
1035 f0 = m_editingSelection.getStartFrame(); | |
1036 } | |
1037 | |
1038 newSelection = Selection(f0, f1); | |
1039 layer->resizeSelection(m_editingSelection, newSelection); | |
1040 } | |
1041 | |
1042 m_manager->removeSelection(m_editingSelection); | |
1043 m_manager->addSelection(newSelection); | |
1044 | |
1045 CommandHistory::getInstance()->endCompoundOperation(); | |
1046 | |
1047 m_editingSelection = Selection(); | |
1048 return true; | |
1049 } | |
1050 | |
1051 void | |
1052 Pane::toolModeChanged() | |
1053 { | |
1054 ViewManager::ToolMode mode = m_manager->getToolMode(); | |
1055 // std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl; | |
1056 | |
1057 switch (mode) { | |
1058 | |
1059 case ViewManager::NavigateMode: | |
1060 setCursor(Qt::PointingHandCursor); | |
1061 break; | |
1062 | |
1063 case ViewManager::SelectMode: | |
1064 setCursor(Qt::ArrowCursor); | |
1065 break; | |
1066 | |
1067 case ViewManager::EditMode: | |
1068 setCursor(Qt::UpArrowCursor); | |
1069 break; | |
1070 | |
1071 case ViewManager::DrawMode: | |
1072 setCursor(Qt::CrossCursor); | |
1073 break; | |
1074 /* | |
1075 case ViewManager::TextMode: | |
1076 setCursor(Qt::IBeamCursor); | |
1077 break; | |
1078 */ | |
1079 } | |
1080 } | |
1081 | |
1082 QString | |
1083 Pane::toXmlString(QString indent, QString extraAttributes) const | |
1084 { | |
1085 return View::toXmlString | |
1086 (indent, | |
1087 QString("type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3") | |
1088 .arg(m_centreLineVisible).arg(height()).arg(extraAttributes)); | |
1089 } | |
1090 | |
1091 | |
1092 #ifdef INCLUDE_MOCFILES | |
1093 #include "Pane.moc.cpp" | |
1094 #endif | |
1095 |