1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #define RG_MODULE_STRING "[ControlRulerWidget]"
19 
20 #include "ControlRulerWidget.h"
21 
22 #include "ControlRuler.h"
23 #include "ControlRulerTabBar.h"
24 #include "ControllerEventsRuler.h"
25 #include "PropertyControlRuler.h"
26 
27 #include "base/BaseProperties.h"
28 #include "base/Composition.h"
29 #include "base/ControlParameter.h"
30 #include "base/Controllable.h"
31 #include "base/Device.h"
32 #include "base/Instrument.h"
33 #include "base/MidiDevice.h"
34 #include "base/MidiTypes.h"  // for PitchBend::EventType
35 #include "base/PropertyName.h"
36 #include "document/RosegardenDocument.h"
37 #include "gui/application/RosegardenMainWindow.h"
38 #include "base/Segment.h"
39 #include "base/Selection.h"  // for EventSelection
40 #include "base/parameterpattern/SelectionSituation.h"
41 #include "base/SoftSynthDevice.h"
42 #include "base/Studio.h"
43 #include "base/Track.h"
44 
45 #include "misc/Debug.h"
46 
47 #include <QVBoxLayout>
48 #include <QStackedWidget>
49 
50 
51 namespace Rosegarden
52 {
53 
54 
ControlRulerWidget()55 ControlRulerWidget::ControlRulerWidget() :
56     m_viewSegment(nullptr),
57     m_controlRulerList(),
58     m_scale(nullptr),
59     m_leftMargin(0),
60     m_currentToolName(),
61     m_pannedRect(),
62     m_selectedElements()
63 {
64     QVBoxLayout *layout = new QVBoxLayout;
65     layout->setContentsMargins(0, 0, 0, 0);
66     layout->setSpacing(0);
67     setLayout(layout);
68 
69     // Stacked Widget
70     m_stackedWidget = new QStackedWidget;
71     layout->addWidget(m_stackedWidget);
72 
73     // Tab Bar
74     m_tabBar = new ControlRulerTabBar;
75 
76     // sizeHint() is the maximum allowed, and the widget is still useful if made
77     // smaller than this, but should never grow larger
78     m_tabBar->setSizePolicy(
79             QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
80 
81     m_tabBar->setDrawBase(false);
82     m_tabBar->setShape(QTabBar::RoundedSouth);
83 
84     layout->addWidget(m_tabBar);
85 
86     connect(m_tabBar, &QTabBar::currentChanged,
87             m_stackedWidget, &QStackedWidget::setCurrentIndex);
88 
89     connect(m_tabBar, &ControlRulerTabBar::tabCloseRequest,
90             this, &ControlRulerWidget::slotRemoveRuler);
91 }
92 
93 void
setViewSegment(ViewSegment * viewSegment)94 ControlRulerWidget::setViewSegment(ViewSegment *viewSegment)
95 {
96     // No change?  Bail.
97     if (viewSegment == m_viewSegment)
98         return;
99 
100     // Disconnect the previous Segment from updates.
101     // ??? Why doesn't the ruler's setViewSegment() do this for us?
102     if (m_viewSegment) {
103         Segment *segment = &(m_viewSegment->getSegment());
104         if (segment) {
105             disconnect(segment, &Segment::contentsChanged,
106                        this, &ControlRulerWidget::slotUpdateRulers);
107         }
108     }
109 
110     m_viewSegment = viewSegment;
111 
112     // For each ruler, set the ViewSegment.
113     for (ControlRuler *ruler : m_controlRulerList) {
114         ruler->setViewSegment(viewSegment);
115     }
116 
117     // Connect current Segment for updates.
118     // ??? Why doesn't the ruler's setViewSegment() do this for us?
119     if (viewSegment) {
120         Segment *segment = &(viewSegment->getSegment());
121         if (segment) {
122             connect(segment, &Segment::contentsChanged,
123                     this, &ControlRulerWidget::slotUpdateRulers);
124         }
125     }
126 }
127 
slotSetCurrentViewSegment(ViewSegment * viewSegment)128 void ControlRulerWidget::slotSetCurrentViewSegment(ViewSegment *viewSegment)
129 {
130     setViewSegment(viewSegment);
131 }
132 
133 void
setRulerScale(RulerScale * scale)134 ControlRulerWidget::setRulerScale(RulerScale *scale)
135 {
136     setRulerScale(scale, 0);
137 }
138 
139 void
setRulerScale(RulerScale * scale,int leftMargin)140 ControlRulerWidget::setRulerScale(RulerScale *scale, int leftMargin)
141 {
142     m_scale = scale;
143     m_leftMargin = leftMargin;
144 
145     // For each ruler, set the ruler scale.
146     for (ControlRuler *ruler : m_controlRulerList) {
147         ruler->setRulerScale(scale);
148     }
149 }
150 
151 const ControlParameter *
getControlParameter2(const Segment & segment,int ccNumber)152 getControlParameter2(const Segment &segment, int ccNumber)
153 {
154     // Get the Device for the Segment.
155 
156     RosegardenDocument *doc = RosegardenMainWindow::self()->getDocument();
157     if (!doc)
158         return nullptr;
159 
160     Instrument *instrument = doc->getStudio().getInstrumentFor(&segment);
161     if (!instrument)
162         return nullptr;
163 
164     Device *device = instrument->getDevice();
165     if (!device)
166         return nullptr;
167 
168     // Get the ControlParameter for the ccNumber.
169 
170     Controllable *controllable = device->getControllable();
171     if (!controllable)
172         return nullptr;
173 
174     return controllable->getControlParameter(Controller::EventType, ccNumber);
175 }
176 
177 void
launchRulers()178 ControlRulerWidget::launchRulers()
179 {
180     if (!m_viewSegment)
181         RG_WARNING << "launchMatrixRulers(): WARNING: No view segment.";
182     if (!m_scale)
183         RG_WARNING << "launchMatrixRulers(): WARNING: No ruler scale.";
184 
185     std::set<Segment::Ruler> rulers;
186 
187     // For each segment ruler set, compute the union of the ruler sets.
188     for (std::shared_ptr<const Segment::RulerSet> segmentRulerSet :
189              m_segmentRulerSets) {
190         rulers.insert(segmentRulerSet->cbegin(),
191                       segmentRulerSet->cend());
192     }
193 
194     // For each ruler, bring up that ruler.
195     for (const Segment::Ruler &ruler : rulers) {
196         if (ruler.type == Controller::EventType) {
197             const ControlParameter *cp = getControlParameter2(
198                     m_viewSegment->getSegment(), ruler.ccNumber);
199             addControlRuler(*cp);
200         } else if (ruler.type == PitchBend::EventType) {
201             RG_DEBUG << "launchInitialRulers(): Launching pitchbend ruler";
202             addControlRuler(ControlParameter::getPitchBend());
203         } else if (ruler.type == BaseProperties::VELOCITY.getName()) {
204             RG_DEBUG << "launchInitialRulers(): Launching velocity ruler";
205             addPropertyRuler(ruler.type);
206         } else {
207             RG_WARNING << "launchInitialRulers(): WARNING: Unexpected ruler in Segment.";
208         }
209     }
210 }
211 
212 void
launchMatrixRulers(std::vector<Segment * > segments)213 ControlRulerWidget::launchMatrixRulers(std::vector<Segment *> segments)
214 {
215     // Launch all rulers from the Segments' ruler lists.
216     // As a separate routine this can be called by the parent after everything
217     // is in place.
218 
219     // For each Segment, get the ruler lists.
220     for (Segment *segment : segments) {
221         if (segment->matrixRulers)
222             m_segmentRulerSets.push_back(segment->matrixRulers);
223     }
224 
225     launchRulers();
226 }
227 
228 void
launchNotationRulers(std::vector<Segment * > segments)229 ControlRulerWidget::launchNotationRulers(std::vector<Segment *> segments)
230 {
231     // For each Segment, get the ruler lists.
232     for (Segment *segment : segments) {
233         if (segment->notationRulers)
234             m_segmentRulerSets.push_back(segment->notationRulers);
235     }
236 
237     launchRulers();
238 }
239 
240 void
togglePropertyRuler(const PropertyName & propertyName)241 ControlRulerWidget::togglePropertyRuler(const PropertyName &propertyName)
242 {
243     // Toggle the *velocity* ruler.  As of 2021 there is only one property
244     // ruler, the velocity ruler.
245 
246     // For each ruler...
247     for (ControlRuler *ruler : m_controlRulerList) {
248         PropertyControlRuler *propruler =
249                 dynamic_cast <PropertyControlRuler *> (ruler);
250         // Not a property ruler?  Try the next one.
251         if (!propruler)
252             continue;
253 
254         // Found it?  Remove and bail.
255         if (propruler->getPropertyName() == propertyName)
256         {
257             removeRuler(ruler);
258             return;
259         }
260     }
261 
262     // Not found, add it.
263     addPropertyRuler(propertyName);
264 }
265 
266 namespace
267 {
hasPitchBend(Segment * segment)268     bool hasPitchBend(Segment *segment)
269     {
270         RosegardenDocument *document = RosegardenMainWindow::self()->getDocument();
271 
272         Track *track =
273                 document->getComposition().getTrackById(segment->getTrack());
274 
275         Instrument *instrument = document->getStudio().
276             getInstrumentById(track->getInstrument());
277 
278         if (!instrument)
279             return false;
280 
281         Controllable *controllable = instrument->getDevice()->getControllable();
282 
283         if (!controllable)
284             return false;
285 
286         // Check whether the device has a pitchbend controller
287         // ??? Why not use
288         //     Controllable::getControlParameter(type, controllerNumber)?
289         for (const ControlParameter &cp : controllable->getControlParameters()) {
290             if (cp.getType() == PitchBend::EventType)
291                 return true;
292         }
293 
294         return false;
295     }
296 }
297 
298 void
togglePitchBendRuler()299 ControlRulerWidget::togglePitchBendRuler()
300 {
301     // No pitch bend?  Bail.
302     // ??? Rude.  We should gray the menu item instead of this.
303     if (!hasPitchBend(&(m_viewSegment->getSegment())))
304         return;
305 
306     // Check whether we already have a pitchbend ruler
307 
308     // For each ruler...
309     for (ControlRuler *ruler : m_controlRulerList) {
310         ControllerEventsRuler *eventRuler =
311                 dynamic_cast<ControllerEventsRuler*>(ruler);
312 
313         // Not a ControllerEventsRuler?  Try the next one.
314         if (!eventRuler)
315             continue;
316 
317         // If we already have a pitchbend ruler, remove it.
318         if (eventRuler->getControlParameter()->getType() ==
319                 PitchBend::EventType)
320         {
321             removeRuler(ruler);
322             return;
323         }
324     }
325 
326     // We don't already have a pitchbend ruler, make one now.
327     addControlRuler(ControlParameter::getPitchBend());
328 }
329 
330 namespace
331 {
332     // Non-O-O approach.  This could be pushed into ControlRuler
333     // and its derivers as getSegmentRuler().
getSegmentRuler(const ControlRuler * controlRuler)334     Segment::Ruler getSegmentRuler(const ControlRuler *controlRuler)
335     {
336         Segment::Ruler segmentRuler;
337 
338         // Is it a PropertyControlRuler?
339         const PropertyControlRuler *pcr =
340                 dynamic_cast<const PropertyControlRuler *>(controlRuler);
341         if (pcr) {
342             segmentRuler.type = BaseProperties::VELOCITY.getName();
343             return segmentRuler;
344         }
345 
346         // Is it a ControllerEventsRuler?
347         const ControllerEventsRuler *cer =
348                 dynamic_cast<const ControllerEventsRuler *>(controlRuler);
349         if (cer) {
350             const ControlParameter *cp = cer->getControlParameter();
351 
352             // Handle pitchbend and CCs (and everything else).
353             segmentRuler.type = cp->getType();
354             if (cp->getType() == Controller::EventType)
355                 segmentRuler.ccNumber = cp->getControllerNumber();
356             return segmentRuler;
357         }
358 
359         return segmentRuler;
360     }
361 }
362 
363 void
removeRuler(ControlRuler * ruler)364 ControlRulerWidget::removeRuler(ControlRuler *ruler)
365 {
366     // Remove from the stacked widget.
367     int index = m_stackedWidget->indexOf(ruler);
368     m_stackedWidget->removeWidget(ruler);
369 
370     // Remove from the tabs.
371     m_tabBar->removeTab(index);
372 
373     // Remove from the list.
374     m_controlRulerList.remove(ruler);
375 
376     Segment::Ruler segmentRuler = getSegmentRuler(ruler);
377 
378     // Remove from all Segment ruler sets.
379     for (std::shared_ptr<Segment::RulerSet> segmentRulerSet :
380              m_segmentRulerSets) {
381         segmentRulerSet->erase(segmentRuler);
382     }
383 
384     // Close the ruler window.
385     delete ruler;
386 }
387 
388 void
slotRemoveRuler(int index)389 ControlRulerWidget::slotRemoveRuler(int index)
390 {
391     ControlRuler *ruler =
392             dynamic_cast<ControlRuler *>(m_stackedWidget->widget(index));
393 
394     removeRuler(ruler);
395 }
396 
397 void
addRuler(ControlRuler * controlRuler,QString name)398 ControlRulerWidget::addRuler(ControlRuler *controlRuler, QString name)
399 {
400     // Add to the stacked widget.
401     m_stackedWidget->addWidget(controlRuler);
402 
403     // Add to tabs.
404     // (Controller names, if translatable, come from AutoLoadStrings.cpp and are
405     // in the QObject context/namespace/whatever.)
406     const int index = m_tabBar->addTab(QObject::tr(name.toStdString().c_str()));
407     m_tabBar->setCurrentIndex(index);
408 
409     // Add to ruler list.
410     m_controlRulerList.push_back(controlRuler);
411 
412     // Configure the ruler.
413     controlRuler->slotSetPannedRect(m_pannedRect);
414     slotSetTool(m_currentToolName);
415 
416     Segment::Ruler segmentRuler = getSegmentRuler(controlRuler);
417 
418     // Add to all Segment ruler sets.
419     for (std::shared_ptr<Segment::RulerSet> segmentRulerSet :
420              m_segmentRulerSets) {
421         segmentRulerSet->insert(segmentRuler);
422     }
423 
424 }
425 
426 void
addControlRuler(const ControlParameter & controlParameter)427 ControlRulerWidget::addControlRuler(const ControlParameter &controlParameter)
428 {
429     // If we're not editing a ViewSegment, bail.
430     if (!m_viewSegment)
431         return;
432 
433     ControlRuler *controlRuler = new ControllerEventsRuler(
434             m_viewSegment, m_scale, this, &controlParameter);
435 
436     controlRuler->setXOffset(m_leftMargin);
437 
438     // Mouse signals.  Forward them from the current ControlRuler.
439     connect(controlRuler, &ControlRuler::mousePress,
440             this, &ControlRulerWidget::mousePress);
441     connect(controlRuler, &ControlRuler::mouseMove,
442             this, &ControlRulerWidget::mouseMove);
443     connect(controlRuler, &ControlRuler::mouseRelease,
444             this, &ControlRulerWidget::mouseRelease);
445 
446     connect(controlRuler, &ControlRuler::rulerSelectionChanged,
447             this, &ControlRulerWidget::slotChildRulerSelectionChanged);
448 
449     addRuler(controlRuler, QString::fromStdString(controlParameter.getName()));
450 
451     // ??? This is required or else we crash.  But we already passed this in
452     //     in the ctor call.  Can we fix this so that we only pass it once?
453     //     Preferably in the ctor call.  PropertyControlRuler appears to do
454     //     this successfully.  See if we can follow its example.
455     controlRuler->setViewSegment(m_viewSegment);
456 }
457 
458 void
addPropertyRuler(const PropertyName & propertyName)459 ControlRulerWidget::addPropertyRuler(const PropertyName &propertyName)
460 {
461     // Note that as of 2021 there is only one property ruler, the
462     // velocity ruler.
463 
464     // If we're not editing a ViewSegment, bail.
465     if (!m_viewSegment)
466         return;
467 
468     PropertyControlRuler *controlRuler = new PropertyControlRuler(
469             propertyName,
470             m_viewSegment,  // viewSegment
471             m_scale,  // scale
472             this);  // parent
473 
474     // ??? The velocity ruler does not yet support selection, so this
475     //     actually does nothing right now.
476     connect(controlRuler, &ControlRuler::rulerSelectionChanged,
477             this, &ControlRulerWidget::slotChildRulerSelectionChanged);
478 
479     connect(controlRuler, &ControlRuler::showContextHelp,
480             this,  &ControlRulerWidget::showContextHelp);
481 
482     controlRuler->setXOffset(m_leftMargin);
483     controlRuler->updateSelection(m_selectedElements);
484 
485     // Little kludge here.  We only have the one property ruler (velocity),
486     // and the string "velocity" wasn't already in a context (any context)
487     // where it could be translated, and "velocity" doesn't look good with
488     // "PitchBend" or "Reverb", so we ask for an explicit tr() here.
489     QString name = QString::fromStdString(propertyName.getName());
490     if (name == "velocity")
491         name = tr("Velocity");
492 
493     addRuler(controlRuler, name);
494 
495     // Update selection drawing in matrix view.
496     emit childRulerSelectionChanged(nullptr);
497 }
498 
499 void
slotSetPannedRect(QRectF pannedRect)500 ControlRulerWidget::slotSetPannedRect(QRectF pannedRect)
501 {
502     m_pannedRect = pannedRect;
503 
504     // For each ruler, pass on the panned rect.
505     for (ControlRuler *ruler : m_controlRulerList) {
506         ruler->slotSetPannedRect(pannedRect);
507     }
508 
509     update();
510 }
511 
512 void
slotSelectionChanged(EventSelection * eventSelection)513 ControlRulerWidget::slotSelectionChanged(EventSelection *eventSelection)
514 {
515     m_selectedElements.clear();
516 
517     if (eventSelection) {
518         // Convert the EventSelection into a vector of ViewElement *.
519 
520         // For each event in the new EventSelection...
521         for (Event *event : eventSelection->getSegmentEvents()) {
522             // Find the corresponding ViewElement.
523             // TODO check if this code is necessary for some reason
524             //      It seems there abundant work done here
525             // ??? Performance: Search within for loop.
526             ViewElementList::iterator viewElementIter =
527                     m_viewSegment->findEvent(event);
528             // Add it to m_selectedElements.
529             m_selectedElements.push_back(*viewElementIter);
530         }
531     }
532 
533     // Send new selection to all PropertyControlRulers.  IOW the velocity ruler.
534     // For each ruler...
535     for (ControlRuler *ruler : m_controlRulerList) {
536         PropertyControlRuler *propertyRuler =
537                 dynamic_cast<PropertyControlRuler *>(ruler);
538         // Is this the velocity ruler?  Then pass on the selection.
539         if (propertyRuler)
540             propertyRuler->updateSelection(m_selectedElements);
541     }
542 }
543 
544 void
slotHoveredOverNoteChanged(int,bool,timeT)545 ControlRulerWidget::slotHoveredOverNoteChanged(int /* evPitch */, bool /* haveEvent */, timeT /* evTime */)
546 {
547     // ??? Since all parameters are unused, can we change the signal we
548     //     connect to (MatrixMover::hoveredOverNoteChanged) to have no
549     //     parameters?  I think we can.
550 
551 //    RG_DEBUG << "slotHoveredOverNoteChanged()";
552 
553     // ??? What does this routine even do.  At first I thought it made sure
554     //     that the velocity bars would move as the notes are dragged around
555     //     on the matrix.  But it does not.  And that makes sense since the
556     //     dragging is a temporary change to the view that doesn't change
557     //     the underlying Segment until the mouse is released.  So we
558     //     wouldn't expect to see the velocity bars moving around during
559     //     the drag.
560     //
561     //     I've removed the code below for now to see if anyone notices.
562 
563 #if 0
564     // ??? This code doesn't appear to do anything.  Removing to see if
565     //     anyone notices.
566     if (m_controlRulerList.size()) {
567         ControlRulerList::iterator it;
568         for (it = m_controlRulerList.begin(); it != m_controlRulerList.end(); ++it) {
569             PropertyControlRuler *pr = dynamic_cast <PropertyControlRuler *> (*it);
570             if (pr) pr->updateSelectedItems();
571         }
572     }
573 #endif
574 }
575 
576 void
slotUpdateRulers(timeT startTime,timeT endTime)577 ControlRulerWidget::slotUpdateRulers(timeT startTime, timeT endTime)
578 {
579     // For each ruler, ask for an update.
580     for (ControlRuler *ruler : m_controlRulerList) {
581         ruler->notationLayoutUpdated(startTime, endTime);
582     }
583 }
584 
585 void
slotSetTool(const QString & toolName)586 ControlRulerWidget::slotSetTool(const QString &toolName)
587 {
588     QString rulerToolName = toolName;
589 
590     // Translate Notation tool names to ruler tool names.
591     if (toolName == "notationselector")
592         rulerToolName = "selector";
593     if (toolName == "notationselectornoties")
594         rulerToolName = "selector";
595     if (toolName == "noterestinserter")
596         rulerToolName = "painter";
597     if (toolName == "notationeraser")
598         rulerToolName = "eraser";
599 
600     m_currentToolName = rulerToolName;
601 
602     // Dispatch to all rulers.
603     for (ControlRuler *ruler : m_controlRulerList) {
604         ruler->setTool(rulerToolName);
605     }
606 }
607 
608 void
slotChildRulerSelectionChanged(EventSelection * s)609 ControlRulerWidget::slotChildRulerSelectionChanged(EventSelection *s)
610 {
611     emit childRulerSelectionChanged(s);
612 }
613 
614 bool
isAnyRulerVisible()615 ControlRulerWidget::isAnyRulerVisible()
616 {
617     return !m_controlRulerList.empty();
618 }
619 
620 ControllerEventsRuler *
getActiveRuler()621 ControlRulerWidget::getActiveRuler()
622 {
623     return dynamic_cast <ControllerEventsRuler *>(
624             m_stackedWidget->currentWidget());
625 }
626 
627 PropertyControlRuler *
getActivePropertyRuler()628 ControlRulerWidget::getActivePropertyRuler()
629 {
630     return dynamic_cast <PropertyControlRuler *>(
631             m_stackedWidget->currentWidget());
632 }
633 
634 bool
hasSelection()635 ControlRulerWidget::hasSelection()
636 {
637     ControllerEventsRuler *ruler = getActiveRuler();
638     if (!ruler)
639         return false;
640 
641     return (ruler->getEventSelection() != nullptr);
642 }
643 
644 EventSelection *
getSelection()645 ControlRulerWidget::getSelection()
646 {
647     ControllerEventsRuler *ruler = getActiveRuler();
648     if (!ruler)
649         return nullptr;
650 
651     return ruler->getEventSelection();
652 }
653 
654 ControlParameter *
getControlParameter()655 ControlRulerWidget::getControlParameter()
656 {
657     ControllerEventsRuler *ruler = getActiveRuler();
658     if (!ruler)
659         return nullptr;
660 
661     return ruler->getControlParameter();
662 }
663 
664 SelectionSituation *
getSituation()665 ControlRulerWidget::getSituation()
666 {
667     ControllerEventsRuler *ruler = getActiveRuler();
668     if (!ruler)
669         return nullptr;
670 
671     EventSelection *selection = ruler->getEventSelection();
672     if (!selection)
673         return nullptr;
674 
675     ControlParameter *cp = ruler->getControlParameter();
676     if (!cp)
677         return nullptr;
678 
679     return new SelectionSituation(cp->getType(), selection);
680 }
681 
682 
683 }
684