diff options
Diffstat (limited to 'src/gui/editors/parameters')
16 files changed, 5473 insertions, 0 deletions
diff --git a/src/gui/editors/parameters/AudioInstrumentParameterPanel.cpp b/src/gui/editors/parameters/AudioInstrumentParameterPanel.cpp new file mode 100644 index 0000000..44a202b --- /dev/null +++ b/src/gui/editors/parameters/AudioInstrumentParameterPanel.cpp @@ -0,0 +1,437 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "AudioInstrumentParameterPanel.h" +#include <qlayout.h> +#include <kapplication.h> + +#include <klocale.h> +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "base/AudioPluginInstance.h" +#include "base/Instrument.h" +#include "base/MidiProgram.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/studio/AudioPluginManager.h" +#include "gui/studio/AudioPlugin.h" +#include "gui/studio/StudioControl.h" +#include "gui/widgets/AudioFaderBox.h" +#include "gui/widgets/AudioVUMeter.h" +#include "gui/widgets/Fader.h" +#include "gui/widgets/Rotary.h" +#include "gui/widgets/AudioRouteMenu.h" +#include "InstrumentParameterPanel.h" +#include "sound/MappedCommon.h" +#include "sound/MappedStudio.h" +#include <qcolor.h> +#include <qframe.h> +#include <qlabel.h> +#include <qpalette.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qstring.h> +#include <qtooltip.h> +#include <qwidget.h> +#include <qsignalmapper.h> + + +namespace Rosegarden +{ + +void +AudioInstrumentParameterPanel::slotSelectAudioLevel(float dB) +{ + if (m_selectedInstrument == 0) + return ; + + if (m_selectedInstrument->getType() == Instrument::Audio || + m_selectedInstrument->getType() == Instrument::SoftSynth) { + m_selectedInstrument->setLevel(dB); + + StudioControl::setStudioObjectProperty + (MappedObjectId(m_selectedInstrument->getMappedId()), + MappedAudioFader::FaderLevel, + MappedObjectValue(dB)); + } + + emit updateAllBoxes(); + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +AudioInstrumentParameterPanel::slotSelectAudioRecordLevel(float dB) +{ + if (m_selectedInstrument == 0) + return ; + + // std::cerr << "AudioInstrumentParameterPanel::slotSelectAudioRecordLevel(" + // << dB << ")" << std::endl; + + if (m_selectedInstrument->getType() == Instrument::Audio) { + m_selectedInstrument->setRecordLevel(dB); + + StudioControl::setStudioObjectProperty + (MappedObjectId(m_selectedInstrument->getMappedId()), + MappedAudioFader::FaderRecordLevel, + MappedObjectValue(dB)); + + emit updateAllBoxes(); + emit instrumentParametersChanged(m_selectedInstrument->getId()); + } +} + +void +AudioInstrumentParameterPanel::slotPluginSelected(InstrumentId instrumentId, + int index, int plugin) +{ + if (!m_selectedInstrument || + instrumentId != m_selectedInstrument->getId()) + return ; + + RG_DEBUG << "AudioInstrumentParameterPanel::slotPluginSelected - " + << "instrument = " << instrumentId + << ", index = " << index + << ", plugin = " << plugin << endl; + + QColor pluginBackgroundColour = Qt::black; + bool bypassed = false; + + QPushButton *button = 0; + QString noneText; + + // updates synth gui button &c: + m_audioFader->slotSetInstrument(&m_doc->getStudio(), m_selectedInstrument); + + if (index == (int)Instrument::SYNTH_PLUGIN_POSITION) { + button = m_audioFader->m_synthButton; + noneText = i18n("<no synth>"); + } else { + button = m_audioFader->m_plugins[index]; + noneText = i18n("<no plugin>"); + } + + if (!button) + return ; + + if (plugin == -1) { + + button->setText(noneText); + QToolTip::add + (button, noneText); + + } else { + + AudioPlugin *pluginClass = m_doc->getPluginManager()->getPlugin(plugin); + + if (pluginClass) { + button->setText(pluginClass->getLabel()); + + QToolTip::add + (button, pluginClass->getLabel()); + + pluginBackgroundColour = pluginClass->getColour(); + } + } + + AudioPluginInstance *inst = + m_selectedInstrument->getPlugin(index); + + if (inst) + bypassed = inst->isBypassed(); + + setButtonColour(index, bypassed, pluginBackgroundColour); + + if (index == (int)Instrument::SYNTH_PLUGIN_POSITION) { + emit changeInstrumentLabel(instrumentId, button->text()); + } +} + +void +AudioInstrumentParameterPanel::slotPluginBypassed(InstrumentId instrumentId, + int pluginIndex, bool bp) +{ + if (!m_selectedInstrument || + instrumentId != m_selectedInstrument->getId()) + return ; + + AudioPluginInstance *inst = + m_selectedInstrument->getPlugin(pluginIndex); + + QColor backgroundColour = Qt::black; // default background colour + + if (inst && inst->isAssigned()) { + AudioPlugin *pluginClass + = m_doc->getPluginManager()->getPlugin( + m_doc->getPluginManager()-> + getPositionByIdentifier(inst->getIdentifier().c_str())); + + /// Set the colour on the button + // + if (pluginClass) + backgroundColour = pluginClass->getColour(); + } + + setButtonColour(pluginIndex, bp, backgroundColour); +} + +void +AudioInstrumentParameterPanel::setButtonColour( + int pluginIndex, bool bypassState, const QColor &colour) +{ + RG_DEBUG << "AudioInstrumentParameterPanel::setButtonColour " + << "pluginIndex = " << pluginIndex + << ", bypassState = " << bypassState + << ", rgb = " << colour.name() << endl; + + QPushButton *button = 0; + + if (pluginIndex == Instrument::SYNTH_PLUGIN_POSITION) { + button = m_audioFader->m_synthButton; + } else { + button = m_audioFader->m_plugins[pluginIndex]; + } + + if (!button) + return ; + + // Set the bypass colour on the plugin button + if (bypassState) { + button-> + setPaletteForegroundColor(kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + + button-> + setPaletteBackgroundColor(kapp->palette(). + color(QPalette::Active, QColorGroup::ButtonText)); + } else if (colour == Qt::black) { + button-> + setPaletteForegroundColor(kapp->palette(). + color(QPalette::Active, QColorGroup::ButtonText)); + + button-> + setPaletteBackgroundColor(kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + } else { + button-> + setPaletteForegroundColor(Qt::white); + + button-> + setPaletteBackgroundColor(colour); + } +} + +AudioInstrumentParameterPanel::AudioInstrumentParameterPanel(RosegardenGUIDoc* doc, QWidget* parent) + : InstrumentParameterPanel(doc, parent), + m_audioFader(new AudioFaderBox(this)) +{ + QGridLayout *gridLayout = new QGridLayout(this, 3, 2, 5, 5); + + // Instrument label : first row, all cols + gridLayout->addMultiCellWidget(m_instrumentLabel, 0, 0, 0, 1, AlignCenter); + + // fader and connect it + gridLayout->addMultiCellWidget(m_audioFader, 1, 1, 0, 1); + + gridLayout->setRowStretch(2, 1); + + connect(m_audioFader, SIGNAL(audioChannelsChanged(int)), + this, SLOT(slotAudioChannels(int))); + + connect(m_audioFader->m_signalMapper, SIGNAL(mapped(int)), + this, SLOT(slotSelectPlugin(int))); + + connect(m_audioFader->m_fader, SIGNAL(faderChanged(float)), + this, SLOT(slotSelectAudioLevel(float))); + + connect(m_audioFader->m_recordFader, SIGNAL(faderChanged(float)), + this, SLOT(slotSelectAudioRecordLevel(float))); + + connect(m_audioFader->m_pan, SIGNAL(valueChanged(float)), + this, SLOT(slotSetPan(float))); + + connect(m_audioFader->m_audioOutput, SIGNAL(changed()), + this, SLOT(slotAudioRoutingChanged())); + + connect(m_audioFader->m_audioInput, SIGNAL(changed()), + this, SLOT(slotAudioRoutingChanged())); + + connect(m_audioFader->m_synthButton, SIGNAL(clicked()), + this, SLOT(slotSynthButtonClicked())); + + connect(m_audioFader->m_synthGUIButton, SIGNAL(clicked()), + this, SLOT(slotSynthGUIButtonClicked())); +} + +void +AudioInstrumentParameterPanel::slotSynthButtonClicked() +{ + slotSelectPlugin(Instrument::SYNTH_PLUGIN_POSITION); +} + +void +AudioInstrumentParameterPanel::slotSynthGUIButtonClicked() +{ + emit showPluginGUI(m_selectedInstrument->getId(), + Instrument::SYNTH_PLUGIN_POSITION); +} + +void +AudioInstrumentParameterPanel::slotSetPan(float pan) +{ + RG_DEBUG << "AudioInstrumentParameterPanel::slotSetPan - " + << "pan = " << pan << endl; + + StudioControl::setStudioObjectProperty + (MappedObjectId(m_selectedInstrument->getMappedId()), + MappedAudioFader::Pan, + MappedObjectValue(pan)); + + m_selectedInstrument->setPan(MidiByte(pan + 100.0)); + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +AudioInstrumentParameterPanel::setAudioMeter(float dBleft, float dBright, + float recDBleft, float recDBright) +{ + // RG_DEBUG << "AudioInstrumentParameterPanel::setAudioMeter: (" << dBleft + // << "," << dBright << ")" << endl; + + if (m_selectedInstrument) { + // Always set stereo, because we have to reflect what's happening + // with the pan setting even on mono tracks + m_audioFader->m_vuMeter->setLevel(dBleft, dBright); + m_audioFader->m_vuMeter->setRecordLevel(recDBleft, recDBright); + } +} + +void +AudioInstrumentParameterPanel::setupForInstrument(Instrument* instrument) +{ + blockSignals(true); + + m_selectedInstrument = instrument; + + m_instrumentLabel->setText(strtoqstr(instrument->getName())); + + m_audioFader->m_recordFader->setFader(instrument->getRecordLevel()); + m_audioFader->m_fader->setFader(instrument->getLevel()); + + m_audioFader->slotSetInstrument(&m_doc->getStudio(), instrument); + + int start = 0; + + if (instrument->getType() == Instrument::SoftSynth) + start = -1; + + for (int i = start; i < int(m_audioFader->m_plugins.size()); i++) { + int index; + QPushButton *button; + QString noneText; + + if (i == -1) { + index = Instrument::SYNTH_PLUGIN_POSITION; + button = m_audioFader->m_synthButton; + noneText = i18n("<no synth>"); + } else { + index = i; + button = m_audioFader->m_plugins[i]; + noneText = i18n("<no plugin>"); + } + + button->show(); + + AudioPluginInstance *inst = instrument->getPlugin(index); + + if (inst && inst->isAssigned()) { + AudioPlugin *pluginClass + = m_doc->getPluginManager()->getPlugin( + m_doc->getPluginManager()-> + getPositionByIdentifier(inst->getIdentifier().c_str())); + + if (pluginClass) { + button->setText(pluginClass->getLabel()); + QToolTip::add + (button, pluginClass->getLabel()); + setButtonColour(index, inst->isBypassed(), + pluginClass->getColour()); + } + } else { + button->setText(noneText); + QToolTip::add + (button, noneText); + setButtonColour(index, inst ? inst->isBypassed() : false, Qt::black); + } + } + + // Set the number of channels on the fader widget + // + m_audioFader->setAudioChannels(instrument->getAudioChannels()); + + // Pan - adjusted backwards + // + m_audioFader->m_pan->setPosition(instrument->getPan() - 100); + + // Tell fader box whether to include e.g. audio input selection + // + m_audioFader->setIsSynth(instrument->getType() == Instrument::SoftSynth); + + blockSignals(false); +} + +void +AudioInstrumentParameterPanel::slotAudioChannels(int channels) +{ + RG_DEBUG << "AudioInstrumentParameterPanel::slotAudioChannels - " + << "channels = " << channels << endl; + + m_selectedInstrument->setAudioChannels(channels); + + StudioControl::setStudioObjectProperty + (MappedObjectId(m_selectedInstrument->getMappedId()), + MappedAudioFader::Channels, + MappedObjectValue(channels)); + + emit instrumentParametersChanged(m_selectedInstrument->getId()); + +} + +void +AudioInstrumentParameterPanel::slotAudioRoutingChanged() +{ + if (m_selectedInstrument) + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +AudioInstrumentParameterPanel::slotSelectPlugin(int index) +{ + if (m_selectedInstrument) { + emit selectPlugin(0, m_selectedInstrument->getId(), index); + } +} + +} +#include "AudioInstrumentParameterPanel.moc" diff --git a/src/gui/editors/parameters/AudioInstrumentParameterPanel.h b/src/gui/editors/parameters/AudioInstrumentParameterPanel.h new file mode 100644 index 0000000..932e6bc --- /dev/null +++ b/src/gui/editors/parameters/AudioInstrumentParameterPanel.h @@ -0,0 +1,107 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_AUDIOINSTRUMENTPARAMETERPANEL_H_ +#define _RG_AUDIOINSTRUMENTPARAMETERPANEL_H_ + +#include "base/MidiProgram.h" +#include "InstrumentParameterPanel.h" +#include <qpixmap.h> +#include <qstring.h> + + +class QWidget; +class QColor; + + +namespace Rosegarden +{ + +class RosegardenGUIDoc; +class Instrument; +class AudioFaderBox; + + +class AudioInstrumentParameterPanel : public InstrumentParameterPanel +{ + Q_OBJECT +public: + AudioInstrumentParameterPanel(RosegardenGUIDoc* doc, QWidget* parent); + + virtual void setupForInstrument(Instrument*); + + // Set the audio meter to a given level for a maximum of + // two channels. + // + void setAudioMeter(float dBleft, float dBright, + float recDBleft, float recDBright); + + // Set the button colour + // + void setButtonColour(int pluginIndex, bool bypassState, + const QColor &color); + +public slots: + // From AudioFaderBox + // + void slotSelectAudioLevel(float dB); + void slotSelectAudioRecordLevel(float dB); + void slotAudioChannels(int channels); + void slotAudioRoutingChanged(); + void slotSelectPlugin(int index); + + // From the parameter box clicks + void slotSetPan(float pan); + + // From Plugin dialog + // + void slotPluginSelected(InstrumentId id, int index, int plugin); + void slotPluginBypassed(InstrumentId id, int pluginIndex, bool bp); + + void slotSynthButtonClicked(); + void slotSynthGUIButtonClicked(); + +signals: + void selectPlugin(QWidget *, InstrumentId, int index); + void instrumentParametersChanged(InstrumentId); + void showPluginGUI(InstrumentId, int index); + void changeInstrumentLabel(InstrumentId id, QString label); + +protected: + //--------------- Data members --------------------------------- + + AudioFaderBox *m_audioFader; + +private: + + QPixmap m_monoPixmap; + QPixmap m_stereoPixmap; + +}; + + +} + +#endif diff --git a/src/gui/editors/parameters/InstrumentParameterBox.cpp b/src/gui/editors/parameters/InstrumentParameterBox.cpp new file mode 100644 index 0000000..8114e0d --- /dev/null +++ b/src/gui/editors/parameters/InstrumentParameterBox.cpp @@ -0,0 +1,265 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "InstrumentParameterBox.h" +#include <qlayout.h> + +#include <klocale.h> +#include "misc/Debug.h" +#include "AudioInstrumentParameterPanel.h" +#include "base/Instrument.h" +#include "base/MidiProgram.h" +#include "document/RosegardenGUIDoc.h" +#include "MIDIInstrumentParameterPanel.h" +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include <ktabwidget.h> +#include <qfont.h> +#include <qframe.h> +#include <qscrollview.h> +#include <qstring.h> +#include <qvbox.h> +#include <qwidget.h> +#include <qwidgetstack.h> + + +namespace Rosegarden +{ + +InstrumentParameterBox::InstrumentParameterBox(RosegardenGUIDoc *doc, + QWidget *parent) + : RosegardenParameterBox(i18n("Instrument"), + i18n("Instrument Parameters"), + parent), + m_widgetStack(new QWidgetStack(this)), + m_noInstrumentParameters(new QVBox(this)), + m_midiInstrumentParameters(new MIDIInstrumentParameterPanel(doc, this)), + m_audioInstrumentParameters(new AudioInstrumentParameterPanel(doc, this)), + m_selectedInstrument(-1), + m_doc(doc), + m_lastShowAdditionalControlsArg(false) +{ + m_widgetStack->setFont(m_font); + m_noInstrumentParameters->setFont(m_font); + m_midiInstrumentParameters->setFont(m_font); + m_audioInstrumentParameters->setFont(m_font); + + bool contains = false; + + std::vector<InstrumentParameterBox*>::iterator it = + instrumentParamBoxes.begin(); + + for (; it != instrumentParamBoxes.end(); it++) + if ((*it) == this) + contains = true; + + if (!contains) + instrumentParamBoxes.push_back(this); + + m_widgetStack->addWidget(m_midiInstrumentParameters); + m_widgetStack->addWidget(m_audioInstrumentParameters); + m_widgetStack->addWidget(m_noInstrumentParameters); + + m_midiInstrumentParameters->adjustSize(); + m_audioInstrumentParameters->adjustSize(); + m_noInstrumentParameters->adjustSize(); + + connect(m_audioInstrumentParameters, SIGNAL(updateAllBoxes()), + this, SLOT(slotUpdateAllBoxes())); + + connect(m_audioInstrumentParameters, + SIGNAL(instrumentParametersChanged(InstrumentId)), + this, + SIGNAL(instrumentParametersChanged(InstrumentId))); + + connect(m_audioInstrumentParameters, + SIGNAL(selectPlugin(QWidget *, InstrumentId, int)), + this, + SIGNAL(selectPlugin(QWidget *, InstrumentId, int))); + + connect(m_audioInstrumentParameters, + SIGNAL(showPluginGUI(InstrumentId, int)), + this, + SIGNAL(showPluginGUI(InstrumentId, int))); + + connect(m_midiInstrumentParameters, SIGNAL(updateAllBoxes()), + this, SLOT(slotUpdateAllBoxes())); + + connect(m_midiInstrumentParameters, + SIGNAL(changeInstrumentLabel(InstrumentId, QString)), + this, SIGNAL(changeInstrumentLabel(InstrumentId, QString))); + + connect(m_audioInstrumentParameters, + SIGNAL(changeInstrumentLabel(InstrumentId, QString)), + this, SIGNAL(changeInstrumentLabel(InstrumentId, QString))); + + connect(m_midiInstrumentParameters, + SIGNAL(instrumentParametersChanged(InstrumentId)), + this, + SIGNAL(instrumentParametersChanged(InstrumentId))); + + // Layout the groups left to right. + + QBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(m_widgetStack); + +} + +InstrumentParameterBox::~InstrumentParameterBox() +{ + // deregister this parameter box + std::vector<InstrumentParameterBox*>::iterator it = + instrumentParamBoxes.begin(); + + for (; it != instrumentParamBoxes.end(); it++) { + if ((*it) == this) { + instrumentParamBoxes.erase(it); + break; + } + } +} + +Instrument * +InstrumentParameterBox::getSelectedInstrument() +{ + if (m_selectedInstrument < 0) return 0; + if (!m_doc) return 0; + return m_doc->getStudio().getInstrumentById(m_selectedInstrument); +} + +QString +InstrumentParameterBox::getPreviousBox(RosegardenParameterArea::Arrangement arrangement) const +{ + return i18n("Track"); +} + +void +InstrumentParameterBox::setAudioMeter(float ch1, float ch2, float ch1r, float ch2r) +{ + m_audioInstrumentParameters->setAudioMeter(ch1, ch2, ch1r, ch2r); +} + +void +InstrumentParameterBox::setDocument(RosegardenGUIDoc* doc) +{ + m_doc = doc; + m_midiInstrumentParameters->setDocument(m_doc); + m_audioInstrumentParameters->setDocument(m_doc); +} + +void +InstrumentParameterBox::slotPluginSelected(InstrumentId id, int index, int plugin) +{ + m_audioInstrumentParameters->slotPluginSelected(id, index, plugin); +} + +void +InstrumentParameterBox::slotPluginBypassed(InstrumentId id, int index, bool bypassState) +{ + m_audioInstrumentParameters->slotPluginBypassed(id, index, bypassState); +} + +void +InstrumentParameterBox::useInstrument(Instrument *instrument) +{ + RG_DEBUG << "useInstrument() - populate Instrument\n"; + + if (instrument == 0) { + m_widgetStack->raiseWidget(m_noInstrumentParameters); + emit instrumentPercussionSetChanged(instrument); + return ; + } + + // ok + if (instrument) { + m_selectedInstrument = instrument->getId(); + } else { + m_selectedInstrument = -1; + } + + // Hide or Show according to Instrument type + // + if (instrument->getType() == Instrument::Audio || + instrument->getType() == Instrument::SoftSynth) { + + m_audioInstrumentParameters->setupForInstrument(getSelectedInstrument()); + m_widgetStack->raiseWidget(m_audioInstrumentParameters); + + } else { // Midi + + m_midiInstrumentParameters->setupForInstrument(getSelectedInstrument()); + m_midiInstrumentParameters->showAdditionalControls(m_lastShowAdditionalControlsArg); + m_widgetStack->raiseWidget(m_midiInstrumentParameters); + emit instrumentPercussionSetChanged(instrument); + + } + +} + +void +InstrumentParameterBox::slotUpdateAllBoxes() +{ + emit instrumentPercussionSetChanged(getSelectedInstrument()); + + std::vector<InstrumentParameterBox*>::iterator it = + instrumentParamBoxes.begin(); + + // To update all open IPBs + // + for (; it != instrumentParamBoxes.end(); it++) { + if ((*it) != this && getSelectedInstrument() && + (*it)->getSelectedInstrument() == getSelectedInstrument()) + (*it)->useInstrument(getSelectedInstrument()); + } +} + +void +InstrumentParameterBox::slotInstrumentParametersChanged(InstrumentId id) +{ + std::vector<InstrumentParameterBox*>::iterator it = + instrumentParamBoxes.begin(); + + blockSignals(true); + + for (; it != instrumentParamBoxes.end(); it++) { + if ((*it)->getSelectedInstrument()) { + if ((*it)->getSelectedInstrument()->getId() == id) { + (*it)->useInstrument((*it)->getSelectedInstrument()); // refresh + } + } + } + + blockSignals(false); +} + +void +InstrumentParameterBox::showAdditionalControls(bool showThem) +{ + m_midiInstrumentParameters->showAdditionalControls(showThem); + m_lastShowAdditionalControlsArg = showThem; +} + +} +#include "InstrumentParameterBox.moc" diff --git a/src/gui/editors/parameters/InstrumentParameterBox.h b/src/gui/editors/parameters/InstrumentParameterBox.h new file mode 100644 index 0000000..f406567 --- /dev/null +++ b/src/gui/editors/parameters/InstrumentParameterBox.h @@ -0,0 +1,126 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_INSTRUMENTPARAMETERBOX_H_ +#define _RG_INSTRUMENTPARAMETERBOX_H_ + +#include "base/MidiProgram.h" +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include <qstring.h> +#include <vector> + + +class QWidgetStack; +class QWidget; +class QFrame; + + +namespace Rosegarden +{ + +class RosegardenGUIDoc; +class MIDIInstrumentParameterPanel; +class Instrument; +class AudioInstrumentParameterPanel; + + +/** + * Display and allow modification of Instrument parameters + */ +class InstrumentParameterBox : public RosegardenParameterBox +{ +Q_OBJECT + +public: + InstrumentParameterBox(RosegardenGUIDoc *doc, + QWidget *parent = 0); + ~InstrumentParameterBox(); + + void useInstrument(Instrument *instrument); + + Instrument* getSelectedInstrument(); + + void setAudioMeter(float dBleft, float dBright, + float recDBleft, float recDBright); + + void setDocument(RosegardenGUIDoc* doc); + + virtual void showAdditionalControls(bool showThem); + + virtual QString getPreviousBox(RosegardenParameterArea::Arrangement) const; + +public slots: + + // To update all InstrumentParameterBoxen for an Instrument. Called + // from one of the parameter panels when something changes. + // + void slotUpdateAllBoxes(); + + // Update InstrumentParameterBoxes that are showing a given instrument. + // Called from the Outside. + // + void slotInstrumentParametersChanged(InstrumentId id); + + // From Plugin dialog + // + void slotPluginSelected(InstrumentId id, int index, int plugin); + void slotPluginBypassed(InstrumentId id, int pluginIndex, bool bp); + +signals: + + void changeInstrumentLabel(InstrumentId id, QString label); + + void selectPlugin(QWidget*, InstrumentId id, int index); + void showPluginGUI(InstrumentId id, int index); + + void instrumentParametersChanged(InstrumentId); + void instrumentPercussionSetChanged(Instrument *); + +protected: + + //--------------- Data members --------------------------------- + QWidgetStack *m_widgetStack; + QFrame *m_noInstrumentParameters; + MIDIInstrumentParameterPanel *m_midiInstrumentParameters; + AudioInstrumentParameterPanel *m_audioInstrumentParameters; + + // -1 if no instrument, InstrumentId otherwise + int m_selectedInstrument; + + // So we can setModified() + // + RosegardenGUIDoc *m_doc; + bool m_lastShowAdditionalControlsArg; +}; + +// Global references +// +static std::vector<InstrumentParameterBox*> instrumentParamBoxes; + + +} + +#endif diff --git a/src/gui/editors/parameters/InstrumentParameterPanel.cpp b/src/gui/editors/parameters/InstrumentParameterPanel.cpp new file mode 100644 index 0000000..9437daf --- /dev/null +++ b/src/gui/editors/parameters/InstrumentParameterPanel.cpp @@ -0,0 +1,61 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "InstrumentParameterPanel.h" + +#include "base/Instrument.h" +#include "document/RosegardenGUIDoc.h" +#include <ksqueezedtextlabel.h> +#include <qfontmetrics.h> +#include <qframe.h> +#include <qlabel.h> +#include <qwidget.h> + + +namespace Rosegarden +{ + +InstrumentParameterPanel::InstrumentParameterPanel(RosegardenGUIDoc *doc, + QWidget* parent) + : QFrame(parent), + m_instrumentLabel(new KSqueezedTextLabel(this)), + m_selectedInstrument(0), + m_doc(doc) +{ + QFontMetrics metrics(m_instrumentLabel->fontMetrics()); + int width25 = metrics.width("1234567890123456789012345"); + + m_instrumentLabel->setFixedWidth(width25); + m_instrumentLabel->setAlignment(Qt::AlignCenter); +} + +void +InstrumentParameterPanel::setDocument(RosegardenGUIDoc* doc) +{ + m_doc = doc; +} + +} +#include "InstrumentParameterPanel.moc" diff --git a/src/gui/editors/parameters/InstrumentParameterPanel.h b/src/gui/editors/parameters/InstrumentParameterPanel.h new file mode 100644 index 0000000..9a794d0 --- /dev/null +++ b/src/gui/editors/parameters/InstrumentParameterPanel.h @@ -0,0 +1,78 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_INSTRUMENTPARAMETERPANEL_H_ +#define _RG_INSTRUMENTPARAMETERPANEL_H_ + +#include <qframe.h> +#include <vector> +#include <utility> + +class QWidget; +class QLabel; + + +namespace Rosegarden +{ + +class RosegardenGUIDoc; +class Instrument; +class Rotary; + +typedef std::pair<Rotary *, QLabel *> RotaryPair; +typedef std::vector<std::pair<int, RotaryPair> > RotaryMap; + + +//////////////////////////////////////////////////////////////////////// + +class InstrumentParameterPanel : public QFrame +{ + Q_OBJECT +public: + InstrumentParameterPanel(RosegardenGUIDoc *doc, QWidget* parent); + + virtual ~InstrumentParameterPanel() {}; + + virtual void setupForInstrument(Instrument*) = 0; + + void setDocument(RosegardenGUIDoc* doc); + + void showAdditionalControls(bool showThem); + +signals: + void updateAllBoxes(); + +protected: + //--------------- Data members --------------------------------- + QLabel *m_instrumentLabel; + Instrument *m_selectedInstrument; + RosegardenGUIDoc *m_doc; +}; + + + +} + +#endif diff --git a/src/gui/editors/parameters/MIDIInstrumentParameterPanel.cpp b/src/gui/editors/parameters/MIDIInstrumentParameterPanel.cpp new file mode 100644 index 0000000..fcd4247 --- /dev/null +++ b/src/gui/editors/parameters/MIDIInstrumentParameterPanel.cpp @@ -0,0 +1,1175 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "MIDIInstrumentParameterPanel.h" +#include <qlayout.h> + +#include "sound/Midi.h" +#include <klocale.h> +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "base/Colour.h" +#include "base/Composition.h" +#include "base/ControlParameter.h" +#include "base/Instrument.h" +#include "base/MidiDevice.h" +#include "base/MidiProgram.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/studio/StudioControl.h" +#include "gui/widgets/Rotary.h" +#include "InstrumentParameterPanel.h" +#include "sound/MappedEvent.h" +#include "sound/MappedInstrument.h" +#include <kcombobox.h> +#include <ksqueezedtextlabel.h> +#include <qcheckbox.h> +#include <qcolor.h> +#include <qfontmetrics.h> +#include <qframe.h> +#include <qhbox.h> +#include <qlabel.h> +#include <qregexp.h> +#include <qsignalmapper.h> +#include <qstring.h> +#include <qwidget.h> +#include <algorithm> + + +namespace Rosegarden +{ + +MIDIInstrumentParameterPanel::MIDIInstrumentParameterPanel(RosegardenGUIDoc *doc, QWidget* parent): + InstrumentParameterPanel(doc, parent), + m_rotaryFrame(0), + m_rotaryMapper(new QSignalMapper(this)) +{ + m_mainGrid = new QGridLayout(this, 10, 3, 2, 1); + + m_connectionLabel = new KSqueezedTextLabel(this); + m_bankValue = new KComboBox(this); + m_channelValue = new KComboBox(this); + m_programValue = new KComboBox(this); + m_variationValue = new KComboBox(this); + m_bankCheckBox = new QCheckBox(this); + m_programCheckBox = new QCheckBox(this); + m_variationCheckBox = new QCheckBox(this); + m_percussionCheckBox = new QCheckBox(this); + + m_bankValue->setSizeLimit(20); + m_programValue->setSizeLimit(20); + m_variationValue->setSizeLimit(20); + + m_bankLabel = new QLabel(i18n("Bank"), this); + m_variationLabel = new QLabel(i18n("Variation"), this); + m_programLabel = new QLabel(i18n("Program"), this); + QLabel *channelLabel = new QLabel(i18n("Channel out"), this); + QLabel *percussionLabel = new QLabel(i18n("Percussion"), this); + + // Ensure a reasonable amount of space in the program dropdowns even + // if no instrument initially selected + QFontMetrics metrics(m_programValue->font()); + int width22 = metrics.width("1234567890123456789012"); + int width25 = metrics.width("1234567890123456789012345"); + + m_bankValue->setMinimumWidth(width22); + m_programValue->setMinimumWidth(width22); + m_variationValue->setMinimumWidth(width22); + + m_connectionLabel->setFixedWidth(width25); + m_connectionLabel->setAlignment(Qt::AlignCenter); + + // Configure the empty final row to accomodate any extra vertical space. + + m_mainGrid->setRowStretch(m_mainGrid->numRows() - 1, 1); + + + m_mainGrid->setColStretch(2, 1); + + m_mainGrid->addMultiCellWidget(m_instrumentLabel, 0, 0, 0, 2, AlignCenter); + m_mainGrid->addMultiCellWidget(m_connectionLabel, 1, 1, 0, 2, AlignCenter); + + m_mainGrid->addMultiCellWidget(channelLabel, 2, 2, 0, 1, AlignLeft); + m_mainGrid->addWidget(m_channelValue, 2, 2, AlignRight); + + m_mainGrid->addMultiCellWidget(percussionLabel, 3, 3, 0, 1, AlignLeft); + m_mainGrid->addWidget(m_percussionCheckBox, 3, 2, AlignRight); + + m_mainGrid->addWidget(m_bankLabel, 4, 0, AlignLeft); + m_mainGrid->addWidget(m_bankCheckBox, 4, 1, AlignRight); + m_mainGrid->addWidget(m_bankValue, 4, 2, AlignRight); + + m_mainGrid->addWidget(m_programLabel, 5, 0, AlignLeft); + m_mainGrid->addWidget(m_programCheckBox, 5, 1, AlignRight); + m_mainGrid->addWidget(m_programValue, 5, 2, AlignRight); + + m_mainGrid->addWidget(m_variationLabel, 6, 0); + m_mainGrid->addWidget(m_variationCheckBox, 6, 1); + m_mainGrid->addWidget(m_variationValue, 6, 2, AlignRight); + + // Populate channel lists + // + for (int i = 0; i < 16; i++) { + m_channelValue->insertItem(QString("%1").arg(i + 1)); + } + + m_channelValue->setSizeLimit(16); + + // Disable these by default - they are activate by their + // checkboxes + // + m_programValue->setDisabled(true); + m_bankValue->setDisabled(true); + m_variationValue->setDisabled(true); + + // Only active if we have an Instrument selected + // + m_percussionCheckBox->setDisabled(true); + m_programCheckBox->setDisabled(true); + m_bankCheckBox->setDisabled(true); + m_variationCheckBox->setDisabled(true); + + // Connect up the toggle boxes + // + connect(m_percussionCheckBox, SIGNAL(toggled(bool)), + this, SLOT(slotTogglePercussion(bool))); + + connect(m_programCheckBox, SIGNAL(toggled(bool)), + this, SLOT(slotToggleProgramChange(bool))); + + connect(m_bankCheckBox, SIGNAL(toggled(bool)), + this, SLOT(slotToggleBank(bool))); + + connect(m_variationCheckBox, SIGNAL(toggled(bool)), + this, SLOT(slotToggleVariation(bool))); + + + // Connect activations + // + connect(m_bankValue, SIGNAL(activated(int)), + this, SLOT(slotSelectBank(int))); + + connect(m_variationValue, SIGNAL(activated(int)), + this, SLOT(slotSelectVariation(int))); + + connect(m_programValue, SIGNAL(activated(int)), + this, SLOT(slotSelectProgram(int))); + + connect(m_channelValue, SIGNAL(activated(int)), + this, SLOT(slotSelectChannel(int))); + + // don't select any of the options in any dropdown + m_programValue->setCurrentItem( -1); + m_bankValue->setCurrentItem( -1); + m_channelValue->setCurrentItem( -1); + m_variationValue->setCurrentItem( -1); + + connect(m_rotaryMapper, SIGNAL(mapped(int)), + this, SLOT(slotControllerChanged(int))); +} + +void +MIDIInstrumentParameterPanel::setupForInstrument(Instrument *instrument) +{ + RG_DEBUG << "MIDIInstrumentParameterPanel::setupForInstrument" << endl; + MidiDevice *md = dynamic_cast<MidiDevice*> + (instrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::setupForInstrument:" + << " No MidiDevice for Instrument " + << instrument->getId() << endl; + return ; + } + + m_selectedInstrument = instrument; + + // Set instrument name + // + m_instrumentLabel->setText(strtoqstr(instrument->getPresentationName())); + + // Set Studio Device name + // + QString connection(strtoqstr(md->getConnection())); + if (connection == "") { + m_connectionLabel->setText(i18n("[ %1 ]").arg(i18n("No connection"))); + } else { + + // remove trailing "(duplex)", "(read only)", "(write only)" etc + connection.replace(QRegExp("\\s*\\([^)0-9]+\\)\\s*$"), ""); + + QString text = i18n("[ %1 ]").arg(connection); + /*QString origText(text); + + QFontMetrics metrics(m_connectionLabel->fontMetrics()); + int maxwidth = metrics.width + ("Program: [X] Acoustic Grand Piano 123");// kind of arbitrary! + + int hlen = text.length() / 2; + while (metrics.width(text) > maxwidth && text.length() > 10) { + --hlen; + text = origText.left(hlen) + "..." + origText.right(hlen); + } + + if (text.length() > origText.length() - 7) text = origText;*/ + m_connectionLabel->setText(text); + } + + // Enable all check boxes + // + m_percussionCheckBox->setDisabled(false); + m_programCheckBox->setDisabled(false); + m_bankCheckBox->setDisabled(false); + m_variationCheckBox->setDisabled(false); + + // Activate all checkboxes + // + m_percussionCheckBox->setChecked(instrument->isPercussion()); + m_programCheckBox->setChecked(instrument->sendsProgramChange()); + m_bankCheckBox->setChecked(instrument->sendsBankSelect()); + m_variationCheckBox->setChecked(instrument->sendsBankSelect()); + + // Basic parameters + // + m_channelValue->setCurrentItem((int)instrument->getMidiChannel()); + + // Check for program change + // + populateBankList(); + populateProgramList(); + populateVariationList(); + + // Setup the ControlParameters + // + setupControllers(md); + + // Set all the positions by controller number + // + for (RotaryMap::iterator it = m_rotaries.begin() ; + it != m_rotaries.end(); ++it) { + MidiByte value = 0; + + // Special cases + // + if (it->first == MIDI_CONTROLLER_PAN) + value = int(instrument->getPan()); + else if (it->first == MIDI_CONTROLLER_VOLUME) + value = int(instrument->getVolume()); + else { + try { + value = instrument->getControllerValue( + MidiByte(it->first)); + } catch (...) { + continue; + } + } + + setRotaryToValue(it->first, int(value)); + } +} + +void +MIDIInstrumentParameterPanel::setupControllers(MidiDevice *md) +{ + if (!m_rotaryFrame) { + m_rotaryFrame = new QFrame(this); + m_mainGrid->addMultiCellWidget(m_rotaryFrame, 8, 8, 0, 2, Qt::AlignHCenter); + m_rotaryGrid = new QGridLayout(m_rotaryFrame, 10, 3, 8, 1); + m_rotaryGrid->addItem(new QSpacerItem(10, 4), 0, 1); + } + + // To cut down on flicker, we avoid destroying and recreating + // widgets as far as possible here. If a label already exists, + // we just set its text; if a rotary exists, we only replace it + // if we actually need a different one. + + Composition &comp = m_doc->getComposition(); + ControlList list = md->getControlParameters(); + + // sort by IPB position + // + std::sort(list.begin(), list.end(), + ControlParameter::ControlPositionCmp()); + + int count = 0; + RotaryMap::iterator rmi = m_rotaries.begin(); + + for (ControlList::iterator it = list.begin(); + it != list.end(); ++it) { + if (it->getIPBPosition() == -1) + continue; + + // Get the knob colour - only if the colour is non-default (>0) + // + QColor knobColour = Qt::black; // special case for Rotary + if (it->getColourIndex() > 0) { + Colour c = + comp.getGeneralColourMap().getColourByIndex + (it->getColourIndex()); + knobColour = QColor(c.getRed(), c.getGreen(), c.getBlue()); + } + + Rotary *rotary = 0; + + if (rmi != m_rotaries.end()) { + + // Update the controller number that is associated with the + // existing rotary widget. + + rmi->first = it->getControllerValue(); + + // Update the properties of the existing rotary widget. + + rotary = rmi->second.first; + int redraw = 0; // 1 -> position, 2 -> all + + if (rotary->getMinValue() != it->getMin()) { + rotary->setMinValue(it->getMin()); + redraw = 1; + } + if (rotary->getMaxValue() != it->getMax()) { + rotary->setMaxValue(it->getMax()); + redraw = 1; + } + if (rotary->getKnobColour() != knobColour) { + rotary->setKnobColour(knobColour); + redraw = 2; + } + if (redraw == 1 || rotary->getPosition() != it->getDefault()) { + rotary->setPosition(it->getDefault()); + if (redraw == 1) + redraw = 0; + } + if (redraw == 2) { + rotary->repaint(); + } + + // Update the controller name that is associated with + // with the existing rotary widget. + + QLabel *label = rmi->second.second; + label->setText(strtoqstr(it->getName())); + + ++rmi; + + } else { + + QHBox *hbox = new QHBox(m_rotaryFrame); + hbox->setSpacing(8); + + float smallStep = 1.0; + + float bigStep = 5.0; + if (it->getMax() - it->getMin() < 10) + bigStep = 1.0; + else if (it->getMax() - it->getMin() < 20) + bigStep = 2.0; + + rotary = new Rotary + (hbox, + it->getMin(), + it->getMax(), + smallStep, + bigStep, + it->getDefault(), + 20, + Rotary::NoTicks, + false, + it->getDefault() == 64); //!!! hacky + + rotary->setKnobColour(knobColour); + + // Add a label + QLabel *label = new KSqueezedTextLabel(strtoqstr(it->getName()), hbox); + + RG_DEBUG << "Adding new widget at " << (count / 2) << "," << (count % 2) << endl; + + // Add the compound widget + // + m_rotaryGrid->addWidget(hbox, count / 2, (count % 2) * 2, AlignLeft); + hbox->show(); + + // Add to list + // + m_rotaries.push_back(std::pair<int, RotaryPair> + (it->getControllerValue(), + RotaryPair(rotary, label))); + + // Connect + // + connect(rotary, SIGNAL(valueChanged(float)), + m_rotaryMapper, SLOT(map())); + + rmi = m_rotaries.end(); + } + + // Add signal mapping + // + m_rotaryMapper->setMapping(rotary, + int(it->getControllerValue())); + + count++; + } + + if (rmi != m_rotaries.end()) { + for (RotaryMap::iterator rmj = rmi; rmj != m_rotaries.end(); ++rmj) { + delete rmj->second.first; + delete rmj->second.second; + } + m_rotaries = std::vector<std::pair<int, RotaryPair> > + (m_rotaries.begin(), rmi); + } + + m_rotaryFrame->show(); +} + +void +MIDIInstrumentParameterPanel::setRotaryToValue(int controller, int value) +{ + /* + RG_DEBUG << "MIDIInstrumentParameterPanel::setRotaryToValue - " + << "controller = " << controller + << ", value = " << value << std::endl; + */ + + for (RotaryMap::iterator it = m_rotaries.begin() ; it != m_rotaries.end(); ++it) { + if (it->first == controller) { + it->second.first->setPosition(float(value)); + return ; + } + } +} + +void +MIDIInstrumentParameterPanel::slotSelectChannel(int index) +{ + if (m_selectedInstrument == 0) + return ; + + m_selectedInstrument->setMidiChannel(index); + + // don't use the emit - use this method instead + StudioControl::sendMappedInstrument( + MappedInstrument(m_selectedInstrument)); + emit updateAllBoxes(); +} + +void +MIDIInstrumentParameterPanel::populateBankList() +{ + if (m_selectedInstrument == 0) + return ; + + m_bankValue->clear(); + m_banks.clear(); + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateBankList:" + << " No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + int currentBank = -1; + BankList banks; + + /* + RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: " + << "variation type is " << md->getVariationType() << endl; + */ + + if (md->getVariationType() == MidiDevice::NoVariations) { + + banks = md->getBanks(m_selectedInstrument->isPercussion()); + + if (!banks.empty()) { + if (m_bankLabel->isHidden()) { + m_bankLabel->show(); + m_bankCheckBox->show(); + m_bankValue->show(); + } + } else { + m_bankLabel->hide(); + m_bankCheckBox->hide(); + m_bankValue->hide(); + } + + for (unsigned int i = 0; i < banks.size(); ++i) { + if (m_selectedInstrument->getProgram().getBank() == banks[i]) { + currentBank = i; + } + } + + } else { + + MidiByteList bytes; + bool useMSB = (md->getVariationType() == MidiDevice::VariationFromLSB); + + if (useMSB) { + bytes = md->getDistinctMSBs(m_selectedInstrument->isPercussion()); + } else { + bytes = md->getDistinctLSBs(m_selectedInstrument->isPercussion()); + } + + if (bytes.size() < 2) { + if (!m_bankLabel->isHidden()) { + m_bankLabel->hide(); + m_bankCheckBox->hide(); + m_bankValue->hide(); + } + } else { + if (m_bankLabel->isHidden()) { + m_bankLabel->show(); + m_bankCheckBox->show(); + m_bankValue->show(); + } + } + + if (useMSB) { + for (unsigned int i = 0; i < bytes.size(); ++i) { + BankList bl = md->getBanksByMSB + (m_selectedInstrument->isPercussion(), bytes[i]); + RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: have " << bl.size() << " variations for msb " << bytes[i] << endl; + + if (bl.size() == 0) + continue; + if (m_selectedInstrument->getMSB() == bytes[i]) { + currentBank = banks.size(); + } + banks.push_back(bl[0]); + } + } else { + for (unsigned int i = 0; i < bytes.size(); ++i) { + BankList bl = md->getBanksByLSB + (m_selectedInstrument->isPercussion(), bytes[i]); + RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: have " << bl.size() << " variations for lsb " << bytes[i] << endl; + if (bl.size() == 0) + continue; + if (m_selectedInstrument->getLSB() == bytes[i]) { + currentBank = banks.size(); + } + banks.push_back(bl[0]); + } + } + } + + for (BankList::const_iterator i = banks.begin(); + i != banks.end(); ++i) { + m_banks.push_back(*i); + m_bankValue->insertItem(strtoqstr(i->getName())); + } + + m_bankValue->setEnabled(m_selectedInstrument->sendsBankSelect()); + + if (currentBank < 0 && !banks.empty()) { + m_bankValue->setCurrentItem(0); + slotSelectBank(0); + } else { + m_bankValue->setCurrentItem(currentBank); + } +} + +void +MIDIInstrumentParameterPanel::populateProgramList() +{ + if (m_selectedInstrument == 0) + return ; + + m_programValue->clear(); + m_programs.clear(); + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateProgramList: No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + /* + RG_DEBUG << "MIDIInstrumentParameterPanel::populateProgramList:" + << " variation type is " << md->getVariationType() << endl; + */ + + MidiBank bank( m_selectedInstrument->isPercussion(), + m_selectedInstrument->getMSB(), + m_selectedInstrument->getLSB()); + + if (m_selectedInstrument->sendsBankSelect()) { + bank = m_selectedInstrument->getProgram().getBank(); + } + + int currentProgram = -1; + + ProgramList programs = md->getPrograms(bank); + + if (!programs.empty()) { + if (m_programLabel->isHidden()) { + m_programLabel->show(); + m_programCheckBox->show(); + m_programValue->show(); + } + } else { + m_programLabel->hide(); + m_programCheckBox->hide(); + m_programValue->hide(); + } + + for (unsigned int i = 0; i < programs.size(); ++i) { + std::string programName = programs[i].getName(); + if (programName != "") { + m_programValue->insertItem(QString("%1. %2") + .arg(programs[i].getProgram() + 1) + .arg(strtoqstr(programName))); + if (m_selectedInstrument->getProgram() == programs[i]) { + currentProgram = m_programs.size(); + } + m_programs.push_back(programs[i]); + } + } + + m_programValue->setEnabled(m_selectedInstrument->sendsProgramChange()); + + if (currentProgram < 0 && !m_programs.empty()) { + m_programValue->setCurrentItem(0); + slotSelectProgram(0); + } else { + m_programValue->setCurrentItem(currentProgram); + + // Ensure that stored program change value is same as the one + // we're now showing (BUG 937371) + // + if (!m_programs.empty()) { + m_selectedInstrument->setProgramChange + ((m_programs[m_programValue->currentItem()]).getProgram()); + } + } +} + +void +MIDIInstrumentParameterPanel::populateVariationList() +{ + if (m_selectedInstrument == 0) + return ; + + m_variationValue->clear(); + m_variations.clear(); + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateVariationList: No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + /* + RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList:" + << " variation type is " << md->getVariationType() << endl; + */ + + if (md->getVariationType() == MidiDevice::NoVariations) { + if (!m_variationLabel->isHidden()) { + m_variationLabel->hide(); + m_variationCheckBox->hide(); + m_variationValue->hide(); + } + return ; + } + + bool useMSB = (md->getVariationType() == MidiDevice::VariationFromMSB); + MidiByteList variations; + + if (useMSB) { + MidiByte lsb = m_selectedInstrument->getLSB(); + variations = md->getDistinctMSBs(m_selectedInstrument->isPercussion(), + lsb); + RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList: have " << variations.size() << " variations for lsb " << lsb << endl; + + } else { + MidiByte msb = m_selectedInstrument->getMSB(); + variations = md->getDistinctLSBs(m_selectedInstrument->isPercussion(), + msb); + RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList: have " << variations.size() << " variations for msb " << msb << endl; + } + + m_variationValue->setCurrentItem( -1); + + MidiProgram defaultProgram; + + if (useMSB) { + defaultProgram = MidiProgram + (MidiBank(m_selectedInstrument->isPercussion(), + 0, + m_selectedInstrument->getLSB()), + m_selectedInstrument->getProgramChange()); + } else { + defaultProgram = MidiProgram + (MidiBank(m_selectedInstrument->isPercussion(), + m_selectedInstrument->getMSB(), + 0), + m_selectedInstrument->getProgramChange()); + } + std::string defaultProgramName = md->getProgramName(defaultProgram); + + int currentVariation = -1; + + for (unsigned int i = 0; i < variations.size(); ++i) { + + MidiProgram program; + + if (useMSB) { + program = MidiProgram + (MidiBank(m_selectedInstrument->isPercussion(), + variations[i], + m_selectedInstrument->getLSB()), + m_selectedInstrument->getProgramChange()); + } else { + program = MidiProgram + (MidiBank(m_selectedInstrument->isPercussion(), + m_selectedInstrument->getMSB(), + variations[i]), + m_selectedInstrument->getProgramChange()); + } + + std::string programName = md->getProgramName(program); + + if (programName != "") { // yes, that is how you know whether it exists + /* + m_variationValue->insertItem(programName == defaultProgramName ? + i18n("(default)") : + strtoqstr(programName)); + */ + m_variationValue->insertItem(QString("%1. %2") + .arg(variations[i] + 1) + .arg(strtoqstr(programName))); + if (m_selectedInstrument->getProgram() == program) { + currentVariation = m_variations.size(); + } + m_variations.push_back(variations[i]); + } + } + + if (currentVariation < 0 && !m_variations.empty()) { + m_variationValue->setCurrentItem(0); + slotSelectVariation(0); + } else { + m_variationValue->setCurrentItem(currentVariation); + } + + if (m_variations.size() < 2) { + if (!m_variationLabel->isHidden()) { + m_variationLabel->hide(); + m_variationCheckBox->hide(); + m_variationValue->hide(); + } + + } else { + //!!! seem to have problems here -- the grid layout doesn't + //like us adding stuff in the middle so if we go from 1 + //visible row (say program) to 2 (program + variation) the + //second one overlaps the control knobs + + if (m_variationLabel->isHidden()) { + m_variationLabel->show(); + m_variationCheckBox->show(); + m_variationValue->show(); + } + + if (m_programValue->width() > m_variationValue->width()) { + m_variationValue->setMinimumWidth(m_programValue->width()); + } else { + m_programValue->setMinimumWidth(m_variationValue->width()); + } + } + + m_variationValue->setEnabled(m_selectedInstrument->sendsBankSelect()); +} + +void +MIDIInstrumentParameterPanel::slotTogglePercussion(bool value) +{ + if (m_selectedInstrument == 0) { + m_percussionCheckBox->setChecked(false); + emit updateAllBoxes(); + return ; + } + + m_selectedInstrument->setPercussion(value); + + populateBankList(); + populateProgramList(); + populateVariationList(); + + sendBankAndProgram(); + + emit changeInstrumentLabel(m_selectedInstrument->getId(), + strtoqstr(m_selectedInstrument-> + getProgramName())); + emit updateAllBoxes(); + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotToggleBank(bool value) +{ + if (m_selectedInstrument == 0) { + m_bankCheckBox->setChecked(false); + emit updateAllBoxes(); + return ; + } + + m_variationCheckBox->setChecked(value); + m_selectedInstrument->setSendBankSelect(value); + + m_bankValue->setDisabled(!value); + populateBankList(); + populateProgramList(); + populateVariationList(); + + sendBankAndProgram(); + + emit changeInstrumentLabel(m_selectedInstrument->getId(), + strtoqstr(m_selectedInstrument-> + getProgramName())); + emit updateAllBoxes(); + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotToggleProgramChange(bool value) +{ + if (m_selectedInstrument == 0) { + m_programCheckBox->setChecked(false); + emit updateAllBoxes(); + return ; + } + + m_selectedInstrument->setSendProgramChange(value); + + m_programValue->setDisabled(!value); + populateProgramList(); + populateVariationList(); + + if (value) + sendBankAndProgram(); + + emit changeInstrumentLabel(m_selectedInstrument->getId(), + strtoqstr(m_selectedInstrument-> + getProgramName())); + emit updateAllBoxes(); + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotToggleVariation(bool value) +{ + if (m_selectedInstrument == 0) { + m_variationCheckBox->setChecked(false); + emit updateAllBoxes(); + return ; + } + + m_bankCheckBox->setChecked(value); + m_selectedInstrument->setSendBankSelect(value); + + m_variationValue->setDisabled(!value); + populateVariationList(); + + sendBankAndProgram(); + + emit changeInstrumentLabel(m_selectedInstrument->getId(), + strtoqstr(m_selectedInstrument-> + getProgramName())); + emit updateAllBoxes(); + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotSelectBank(int index) +{ + if (m_selectedInstrument == 0) + return ; + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectBank: No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + const MidiBank *bank = &m_banks[index]; + + bool change = false; + + if (md->getVariationType() != MidiDevice::VariationFromLSB) { + if (m_selectedInstrument->getLSB() != bank->getLSB()) { + m_selectedInstrument->setLSB(bank->getLSB()); + change = true; + } + } + if (md->getVariationType() != MidiDevice::VariationFromMSB) { + if (m_selectedInstrument->getMSB() != bank->getMSB()) { + m_selectedInstrument->setMSB(bank->getMSB()); + change = true; + } + } + + populateProgramList(); + + if (change) { + sendBankAndProgram(); + emit updateAllBoxes(); + } + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotSelectProgram(int index) +{ + const MidiProgram *prg = &m_programs[index]; + if (prg == 0) { + RG_DEBUG << "program change not found in bank" << endl; + return ; + } + + bool change = false; + if (m_selectedInstrument->getProgramChange() != prg->getProgram()) { + m_selectedInstrument->setProgramChange(prg->getProgram()); + change = true; + } + + populateVariationList(); + + if (change) { + sendBankAndProgram(); + emit changeInstrumentLabel(m_selectedInstrument->getId(), + strtoqstr(m_selectedInstrument-> + getProgramName())); + emit updateAllBoxes(); + } + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::slotSelectVariation(int index) +{ + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectVariation: No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + if (index < 0 || index > int(m_variations.size())) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectVariation: index " << index << " out of range" << endl; + return ; + } + + MidiByte v = m_variations[index]; + + bool change = false; + + if (md->getVariationType() == MidiDevice::VariationFromLSB) { + if (m_selectedInstrument->getLSB() != v) { + m_selectedInstrument->setLSB(v); + change = true; + } + } else if (md->getVariationType() == MidiDevice::VariationFromMSB) { + if (m_selectedInstrument->getMSB() != v) { + m_selectedInstrument->setMSB(v); + change = true; + } + } + + if (change) { + sendBankAndProgram(); + } + + emit instrumentParametersChanged(m_selectedInstrument->getId()); +} + +void +MIDIInstrumentParameterPanel::sendBankAndProgram() +{ + if (m_selectedInstrument == 0) + return ; + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) { + RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::sendBankAndProgram: No MidiDevice for Instrument " + << m_selectedInstrument->getId() << endl; + return ; + } + + if (m_selectedInstrument->sendsBankSelect()) { + + // Send the bank select message before any PC message + // + MappedEvent mEMSB(m_selectedInstrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_BANK_MSB, + m_selectedInstrument->getMSB()); + + RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - " + << "sending MSB = " + << int(m_selectedInstrument->getMSB()) + << endl; + + StudioControl::sendMappedEvent(mEMSB); + + MappedEvent mELSB(m_selectedInstrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_BANK_LSB, + m_selectedInstrument->getLSB()); + + RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - " + << "sending LSB = " + << int(m_selectedInstrument->getLSB()) + << endl; + + StudioControl::sendMappedEvent(mELSB); + } + + MappedEvent mE(m_selectedInstrument->getId(), + MappedEvent::MidiProgramChange, + m_selectedInstrument->getProgramChange(), + (MidiByte)0); + + RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - " + << "sending program change = " + << int(m_selectedInstrument->getProgramChange()) + << endl; + + + // Send the controller change + // + StudioControl::sendMappedEvent(mE); +} + +void +MIDIInstrumentParameterPanel::slotControllerChanged(int controllerNumber) +{ + + RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - " + << "controller = " << controllerNumber << "\n"; + + + if (m_selectedInstrument == 0) + return ; + + MidiDevice *md = dynamic_cast<MidiDevice*> + (m_selectedInstrument->getDevice()); + if (!md) + return ; + + /* + ControlParameter *controller = + md->getControlParameter(MidiByte(controllerNumber)); + */ + + int value = getValueFromRotary(controllerNumber); + + if (value == -1) { + RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - " + << "couldn't get value of rotary for controller " + << controllerNumber << endl; + return ; + } + + + // two special cases + if (controllerNumber == int(MIDI_CONTROLLER_PAN)) { + float adjValue = value; + if (m_selectedInstrument->getType() == Instrument::Audio || + m_selectedInstrument->getType() == Instrument::SoftSynth) + value += 100; + + m_selectedInstrument->setPan(MidiByte(adjValue)); + } else if (controllerNumber == int(MIDI_CONTROLLER_VOLUME)) { + m_selectedInstrument->setVolume(MidiByte(value)); + } else // just set the controller (this will create it on the instrument if + // it doesn't exist) + { + m_selectedInstrument->setControllerValue(MidiByte(controllerNumber), + MidiByte(value)); + + RG_DEBUG << "SET CONTROLLER VALUE (" << controllerNumber << ") = " << value << endl; + } + /* + else + { + RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - " + << "no controller retrieved\n"; + return; + } + */ + + MappedEvent mE(m_selectedInstrument->getId(), + MappedEvent::MidiController, + (MidiByte)controllerNumber, + (MidiByte)value); + StudioControl::sendMappedEvent(mE); + + emit updateAllBoxes(); + emit instrumentParametersChanged(m_selectedInstrument->getId()); + +} + +int +MIDIInstrumentParameterPanel::getValueFromRotary(int rotary) +{ + for (RotaryMap::iterator it = m_rotaries.begin(); it != m_rotaries.end(); ++it) { + if (it->first == rotary) + return int(it->second.first->getPosition()); + } + + return -1; +} + +void +MIDIInstrumentParameterPanel::showAdditionalControls(bool showThem) +{ + m_instrumentLabel->setShown(showThem); + int index = 0; + for (RotaryMap::iterator it = m_rotaries.begin(); it != m_rotaries.end(); ++it) { + it->second.first->parentWidget()->setShown(showThem || (index < 8)); + //it->second.first->setShown(showThem || (index < 8)); + //it->second.second->setShown(showThem || (index < 8)); + index++; + } +} + +} +#include "MIDIInstrumentParameterPanel.moc" diff --git a/src/gui/editors/parameters/MIDIInstrumentParameterPanel.h b/src/gui/editors/parameters/MIDIInstrumentParameterPanel.h new file mode 100644 index 0000000..7f1a1c5 --- /dev/null +++ b/src/gui/editors/parameters/MIDIInstrumentParameterPanel.h @@ -0,0 +1,137 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_MIDIINSTRUMENTPARAMETERPANEL_H_ +#define _RG_MIDIINSTRUMENTPARAMETERPANEL_H_ + +#include "base/MidiProgram.h" +#include "base/MidiDevice.h" +#include "InstrumentParameterPanel.h" +#include <qstring.h> + + +class QWidget; +class QSignalMapper; +class QLabel; +class QGridLayout; +class QFrame; +class QCheckBox; +class KComboBox; + + +namespace Rosegarden +{ + +class RosegardenGUIDoc; +class MidiDevice; +class Instrument; + + +class MIDIInstrumentParameterPanel : public InstrumentParameterPanel +{ + Q_OBJECT +public: + + MIDIInstrumentParameterPanel(RosegardenGUIDoc *doc, QWidget* parent); + + void setupControllers(MidiDevice *); // setup ControlParameters on box + + virtual void setupForInstrument(Instrument*); + + void showAdditionalControls(bool showThem); + +signals: + void changeInstrumentLabel(InstrumentId id, QString label); + void instrumentParametersChanged(InstrumentId); + +public slots: + void slotSelectProgram(int index); + void slotSelectBank(int index); + void slotSelectVariation(int index); + void slotSelectChannel(int index); + //void slotSelectInputChannel(int index); + + void slotControllerChanged(int index); + + void slotTogglePercussion(bool value); + void slotToggleProgramChange(bool value); + void slotToggleBank(bool value); + void slotToggleVariation(bool value); + +protected: + + // fill (or hide) bank combo based on whether the instrument is percussion + void populateBankList(); + + // fill program combo based on current bank + void populateProgramList(); + + // fill (or hide) variation combo based on current bank and program + void populateVariationList(); + + // send the bank and program events relevant to this instrument + void sendBankAndProgram(); + + // get value of a specific rotary (keyed by controller value) + int getValueFromRotary(int rotary); + + // set rotary to value + void setRotaryToValue(int controller, int value); + + //--------------- Data members --------------------------------- + + QLabel *m_connectionLabel; + + KComboBox *m_bankValue; + KComboBox *m_variationValue; + KComboBox *m_channelValue; + KComboBox *m_programValue; + //KComboBox *m_channelInValue; + + QCheckBox *m_percussionCheckBox; + QCheckBox *m_bankCheckBox; + QCheckBox *m_variationCheckBox; + QCheckBox *m_programCheckBox; + + QLabel *m_bankLabel; + QLabel *m_variationLabel; + QLabel *m_programLabel; + + QGridLayout *m_mainGrid; + QFrame *m_rotaryFrame; + QGridLayout *m_rotaryGrid; + RotaryMap m_rotaries; + QSignalMapper *m_rotaryMapper; + + BankList m_banks; + ProgramList m_programs; + MidiByteList m_variations; +}; + + + +} + +#endif diff --git a/src/gui/editors/parameters/RosegardenParameterArea.cpp b/src/gui/editors/parameters/RosegardenParameterArea.cpp new file mode 100644 index 0000000..968c737 --- /dev/null +++ b/src/gui/editors/parameters/RosegardenParameterArea.cpp @@ -0,0 +1,227 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + This file Copyright 2006 Martin Shepherd <[email protected]>. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "RosegardenParameterArea.h" + +#include "RosegardenParameterBox.h" +#include <ktabwidget.h> +#include <qfont.h> +#include <qframe.h> +#include <qpoint.h> +#include <qscrollview.h> +#include <qstring.h> +#include <qvbox.h> +#include <qlayout.h> +#include <qvgroupbox.h> +#include <qwidget.h> +#include <qwidgetstack.h> +#include <iostream> +#include <set> + + +namespace Rosegarden +{ + +RosegardenParameterArea::RosegardenParameterArea(QWidget *parent, + const char *name, WFlags f) + : QWidgetStack(parent, name, f), + m_style(RosegardenParameterArea::CLASSIC_STYLE), + m_scrollView(new QScrollView(this, 0, Qt::WStaticContents)), + m_classic(new QVBox(m_scrollView->viewport())), + m_tabBox(new KTabWidget(this)), + m_active(0), + m_spacing(0) +{ + m_scrollView->addChild(m_classic); + m_scrollView->setHScrollBarMode(QScrollView::AlwaysOff); + m_scrollView->setVScrollBarMode(QScrollView::Auto); + m_scrollView->setResizePolicy(QScrollView::AutoOneFit); + + // Install the classic-style VBox widget in the widget-stack. + + addWidget(m_scrollView, CLASSIC_STYLE); + + // Install the widget that implements the tab-style to the widget-stack. + + addWidget(m_tabBox, TAB_BOX_STYLE); + +} + +void RosegardenParameterArea::addRosegardenParameterBox( + RosegardenParameterBox *b) +{ + // Check that the box hasn't been added before. + + for (unsigned int i = 0; i < m_parameterBoxes.size(); i++) { + if (m_parameterBoxes[i] == b) + return ; + } + + // Append the parameter box to the list to be displayed. + + m_parameterBoxes.push_back(b); + + m_scrollView->setMinimumWidth(std::max(m_scrollView->minimumWidth(), + b->sizeHint().width()) + 8); + + // Create a titled group box for the parameter box, parented by the + // classic layout widget, so that it can be used to provide a title + // and outline, in classic mode. Add this container to an array that + // parallels the above array of parameter boxes. + + QVGroupBox *box = new QVGroupBox(b->getLongLabel(), m_classic); + box->layout()->setMargin( 4 ); // about half the default value + QFont f; + f.setBold( true ); + box->setFont( f ); + m_groupBoxes.push_back(box); + + if (m_spacing) + delete m_spacing; + m_spacing = new QFrame(m_classic); + m_classic->setStretchFactor(m_spacing, 100); + + // Add the parameter box to the current container of the displayed + // widgets, unless the current container has been set up yet. + + if (m_active) + moveWidget(0, m_active, b); + + // Queue a redisplay of the parameter area, to incorporate the new box. + + update(); +} + +void RosegardenParameterArea::setArrangement(Arrangement style) +{ + // Lookup the container of the specified style. + + QWidget *container; + switch (style) { + case CLASSIC_STYLE: + container = m_classic; + break; + case TAB_BOX_STYLE: + container = m_tabBox; + break; + default: + std::cerr << "setArrangement() was passed an unknown arrangement style." + << std::endl; + return ; + } + + // Does the current container of the parameter-box widgets differ + // from the one that is associated with the currently configured + // style? + + if (container != m_active) { + + // Move the parameter boxes from the old container to the new one. + + std::vector<RosegardenParameterBox *> sorted; + std::set<RosegardenParameterBox *> unsorted; + + for (unsigned int i = 0; i < m_parameterBoxes.size(); i++) { + unsorted.insert(m_parameterBoxes[i]); + } + + QString previous = ""; + + while (!unsorted.empty()) { + std::set<RosegardenParameterBox *>::iterator i = unsorted.begin(); + bool have = false; + while (i != unsorted.end()) { + if ((*i)->getPreviousBox(style) == previous) { + sorted.push_back(*i); + previous = (*i)->getShortLabel(); + unsorted.erase(i); + have = true; + break; + } + ++i; + } + if (!have) { + while (!unsorted.empty()) { + sorted.push_back(*unsorted.begin()); + unsorted.erase(unsorted.begin()); + } + break; + } + } + + for (std::vector<RosegardenParameterBox *>::iterator i = sorted.begin(); + i != sorted.end(); ++i) { + moveWidget(m_active, container, *i); + (*i)->showAdditionalControls(style == TAB_BOX_STYLE); + } + + // Switch the widget stack to displaying the new container. + + raiseWidget(style); + } + + // Record the identity of the active container, and the associated + // arrangement style. + + m_active = container; + m_style = style; +} + +void RosegardenParameterArea::moveWidget(QWidget *old_container, + QWidget *new_container, + RosegardenParameterBox *box) +{ + // Remove any state that is associated with the parameter boxes, + // from the active container. + + if (old_container == m_classic) { + ; + } else if (old_container == m_tabBox) { + m_tabBox->removePage(box); + } + + // Reparent the parameter box, and perform any container-specific + // configuration. + + if (new_container == m_classic) { + int index = 0; + while (index < m_parameterBoxes.size()) { + if (box == m_parameterBoxes[index]) + break; + ++index; + } + if (index < m_parameterBoxes.size()) { + box->reparent(m_groupBoxes[index], 0, QPoint(0, 0), FALSE); + } + } else if (new_container == m_tabBox) { + box->reparent(new_container, 0, QPoint(0, 0), FALSE); + m_tabBox->insertTab(box, box->getShortLabel()); + } +} + +} +#include "RosegardenParameterArea.moc" diff --git a/src/gui/editors/parameters/RosegardenParameterArea.h b/src/gui/editors/parameters/RosegardenParameterArea.h new file mode 100644 index 0000000..1236a43 --- /dev/null +++ b/src/gui/editors/parameters/RosegardenParameterArea.h @@ -0,0 +1,108 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + This file Copyright 2006 Martin Shepherd <[email protected]>. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_ROSEGARDENPARAMETERAREA_H_ +#define _RG_ROSEGARDENPARAMETERAREA_H_ + +#include <qwidgetstack.h> +#include <vector> + + +class QWidget; +class QVGroupBox; +class QVBox; +class QScrollView; +class KTabWidget; + + +namespace Rosegarden +{ + +class RosegardenParameterBox; + + +/** + * A widget that arranges a set of Rosegarden parameter-box widgets + * within a frame, in a dynamically configurable manner. + */ +class RosegardenParameterArea : public QWidgetStack +{ + Q_OBJECT +public: + + // Create the parameter display area. + + RosegardenParameterArea(QWidget *parent=0, const char *name=0, WFlags f=0); + + // Add a rosegarden parameter box to the list that are to be displayed. + + void addRosegardenParameterBox(RosegardenParameterBox *b); + + + // List the supported methods of arranging the various parameter-box + // widgets within the parameter area. + + enum Arrangement { + CLASSIC_STYLE, // A simple vertical tiling of parameter-box widgets. + TAB_BOX_STYLE // A horizontal list of tabs, displaying one box at a time. + }; + + // Redisplay the widgets with a different layout style. + + void setArrangement(Arrangement style); + +protected: +private: + Arrangement m_style; // The current layout style. + + // The list of parameter box widgets that are being displayed by this + // widget. + + std::vector<RosegardenParameterBox *> m_parameterBoxes; + + // Create a parallel array of group boxes, to be used when the + // corresponding parameter box widget needs to be enclosed by a + // titled outline. + + std::vector<QVGroupBox *> m_groupBoxes; + + // Move a RosegardenParameterBox widget from one container to another. + + void moveWidget(QWidget *old_container, QWidget *new_container, + RosegardenParameterBox *box); + + QScrollView *m_scrollView; // Holds the m_classic container + QVBox *m_classic; // The container widget for m_style==CLASSIC_STYLE. + KTabWidget *m_tabBox; // The container widget for m_style==TAB_BOX_STYLE. + QWidget *m_active; // The current container widget. + QWidget *m_spacing; +}; + + +} + +#endif diff --git a/src/gui/editors/parameters/RosegardenParameterBox.cpp b/src/gui/editors/parameters/RosegardenParameterBox.cpp new file mode 100644 index 0000000..7d9100c --- /dev/null +++ b/src/gui/editors/parameters/RosegardenParameterBox.cpp @@ -0,0 +1,89 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "RosegardenParameterBox.h" + +#include "RosegardenParameterArea.h" +#include <ktabwidget.h> +#include <qfont.h> +#include <qframe.h> +#include <qscrollview.h> +#include <qstring.h> +#include <qvbox.h> +#include <qwidget.h> +#include <qwidgetstack.h> + + +namespace Rosegarden +{ + +RosegardenParameterBox::RosegardenParameterBox(const QString &shortLabel, + const QString &longLabel, + QWidget *parent, + const char *name) : + QFrame(parent, name), + m_shortLabel(shortLabel), + m_longLabel(longLabel), + m_mode(LANDSCAPE_MODE) +{ + init(); +} + +void RosegardenParameterBox::init() +{ + QFont plainFont; + plainFont.setPointSize(plainFont.pointSize() * 95 / 100); + if (plainFont.pixelSize() > 14) + plainFont.setPixelSize(14); + plainFont.setBold(false); + m_font = plainFont; + + QFont boldFont; + boldFont.setPointSize(int(boldFont.pointSize() * 9.5 / 10.0 + 0.5)); + if (boldFont.pixelSize() > 14) + boldFont.setPixelSize(14); + boldFont.setBold(true); + + setFont(boldFont); +} + +QString RosegardenParameterBox::getShortLabel() const +{ + return m_shortLabel; +} + +QString RosegardenParameterBox::getLongLabel() const +{ + return m_longLabel; +} + +QString RosegardenParameterBox::getPreviousBox(RosegardenParameterArea::Arrangement) const +{ + // No ordering known -- depends on subclasses + return ""; +} + +} +#include "RosegardenParameterBox.moc" diff --git a/src/gui/editors/parameters/RosegardenParameterBox.h b/src/gui/editors/parameters/RosegardenParameterBox.h new file mode 100644 index 0000000..6f17358 --- /dev/null +++ b/src/gui/editors/parameters/RosegardenParameterBox.h @@ -0,0 +1,92 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_ROSEGARDENPARAMETERBOX_H_ +#define _RG_ROSEGARDENPARAMETERBOX_H_ + +#include "RosegardenParameterArea.h" +#include <qfont.h> +#include <qframe.h> +#include <qstring.h> +#include <klocale.h> + + +class QWidget; + + +namespace Rosegarden +{ + + + +/** + * A flat QFrame, in which a group of parameters can be laid out. + * Virtual method functions are defined for for requesting a layout + * style, and returning the single-word to use for labelling the + * box. + */ + +class RosegardenParameterBox : public QFrame +{ + Q_OBJECT +public: + RosegardenParameterBox(const QString &shortLabel, // e.g. i18n("Track") + const QString &longLabel, // e.g. i18n("Track Parameters") + QWidget *parent = 0, + const char *name = 0); + + // Ask for a one-word string that can be used to label the widget. + QString getShortLabel() const; + + // Ask for the full label (e.g. short-label "Parameters") + QString getLongLabel() const; + + // Get the short label of the prior parameter box (to establish an ordering) + virtual QString getPreviousBox(RosegardenParameterArea::Arrangement) const; + + virtual void showAdditionalControls(bool) = 0; + +protected: + void init(); + + // List the layout styles that may be requested via a call to setStyle(). + + enum LayoutMode { + LANDSCAPE_MODE, // Optimize the layout for a tall and narrow parent. + PORTRAIT_MODE // Optimize the layout for a short and wide parent. + }; + + void setLayoutMode(LayoutMode mode); + + QFont m_font; + QString m_shortLabel; // The string that containers can use for labelling and identification + QString m_longLabel; // The full title + LayoutMode m_mode; // The current layout mode. +}; + + +} + +#endif diff --git a/src/gui/editors/parameters/SegmentParameterBox.cpp b/src/gui/editors/parameters/SegmentParameterBox.cpp new file mode 100644 index 0000000..c17cbe2 --- /dev/null +++ b/src/gui/editors/parameters/SegmentParameterBox.cpp @@ -0,0 +1,1214 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "SegmentParameterBox.h" +#include <qlayout.h> +#include <kapplication.h> + +#include <klocale.h> +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "document/ConfigGroups.h" +#include "base/Colour.h" +#include "base/ColourMap.h" +#include "base/Composition.h" +#include "base/MidiProgram.h" +#include "base/NotationTypes.h" +#include "base/BasicQuantizer.h" +#include "base/RealTime.h" +#include "base/Segment.h" +#include "base/Selection.h" +#include "commands/segment/SegmentChangeQuantizationCommand.h" +#include "commands/segment/SegmentColourCommand.h" +#include "commands/segment/SegmentColourMapCommand.h" +#include "commands/segment/SegmentCommandRepeat.h" +#include "commands/segment/SegmentLabelCommand.h" +#include "document/MultiViewCommandHistory.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/dialogs/PitchPickerDialog.h" +#include "gui/editors/notation/NotationStrings.h" +#include "gui/editors/notation/NotePixmapFactory.h" +#include "gui/general/GUIPalette.h" +#include "gui/widgets/ColourTable.h" +#include "gui/widgets/TristateCheckBox.h" +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include <kcolordialog.h> +#include <kcombobox.h> +#include <kcommand.h> +#include <kconfig.h> +#include <klineeditdlg.h> +#include <ktabwidget.h> +#include <qbutton.h> +#include <qcheckbox.h> +#include <qcolor.h> +#include <qdialog.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qframe.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qscrollview.h> +#include <qspinbox.h> +#include <qstring.h> +#include <qtooltip.h> +#include <qvbox.h> +#include <qwidget.h> +#include <qwidgetstack.h> + + +namespace Rosegarden +{ + +SegmentParameterBox::SegmentParameterBox(RosegardenGUIDoc* doc, + QWidget *parent) + : RosegardenParameterBox(i18n("Segment"), + i18n("Segment Parameters"), + parent), + m_highestPlayable(127), + m_lowestPlayable(0), + m_standardQuantizations(BasicQuantizer::getStandardQuantizations()), + m_doc(doc), + m_transposeRange(48) +{ + initBox(); + + m_doc->getComposition().addObserver(this); + + connect(getCommandHistory(), SIGNAL(commandExecuted()), + this, SLOT(update())); +} + +SegmentParameterBox::~SegmentParameterBox() +{ + if (!isCompositionDeleted()) { + m_doc->getComposition().removeObserver(this); + } +} + +void +SegmentParameterBox::initBox() +{ + QFont font(m_font); + + QFontMetrics fontMetrics(font); + // magic numbers: 13 is the height of the menu pixmaps, 10 is just 10 + //int comboHeight = std::max(fontMetrics.height(), 13) + 10; + int width = fontMetrics.width("12345678901234567890"); + + // QFrame *frame = new QFrame(this); + QGridLayout *gridLayout = new QGridLayout(this, 8, 6, 4, 2); + + QLabel *label = new QLabel(i18n("Label"), this); + QLabel *repeatLabel = new QLabel(i18n("Repeat"), this); + QLabel *quantizeLabel = new QLabel(i18n("Quantize"), this); + QLabel *transposeLabel = new QLabel(i18n("Transpose"), this); + QLabel *delayLabel = new QLabel(i18n("Delay"), this); + QLabel *colourLabel = new QLabel(i18n("Color"), this); +// m_autoFadeLabel = new QLabel(i18n("Audio auto-fade"), this); +// m_fadeInLabel = new QLabel(i18n("Fade in"), this); +// m_fadeOutLabel = new QLabel(i18n("Fade out"), this); +// m_rangeLabel = new QLabel(i18n("Range"), this); + + // Label .. + m_label = new QLabel(this); + m_label->setFont(font); + m_label->setFixedWidth(width); + //m_label->setFixedHeight(comboHeight); + m_label->setFrameStyle(QFrame::Panel | QFrame::Sunken); + + // .. and edit button + m_labelButton = new QPushButton(i18n("Edit"), this); + m_labelButton->setFont(font); + // m_labelButton->setFixedWidth(50); + + connect(m_labelButton, SIGNAL(released()), + SLOT(slotEditSegmentLabel())); + + m_repeatValue = new TristateCheckBox(this); + m_repeatValue->setFont(font); + //m_repeatValue->setFixedHeight(comboHeight); + + // handle state changes + connect(m_repeatValue, SIGNAL(pressed()), SLOT(slotRepeatPressed())); + + // non-reversing motif style read-only combo + m_quantizeValue = new KComboBox(this); + m_quantizeValue->setFont(font); + //m_quantizeValue->setFixedHeight(comboHeight); + + // handle quantize changes from drop down + connect(m_quantizeValue, SIGNAL(activated(int)), + SLOT(slotQuantizeSelected(int))); + + // reversing motif style read-write combo + m_transposeValue = new KComboBox(this); + m_transposeValue->setFont(font); + //m_transposeValue->setFixedHeight(comboHeight); + + // handle transpose combo changes + connect(m_transposeValue, SIGNAL(activated(int)), + SLOT(slotTransposeSelected(int))); + + // and text changes + connect(m_transposeValue, SIGNAL(textChanged(const QString&)), + SLOT(slotTransposeTextChanged(const QString&))); + + // reversing motif style read-write combo + m_delayValue = new KComboBox(this); + m_delayValue->setFont(font); + //m_delayValue->setFixedHeight(comboHeight); + + // handle delay combo changes + connect(m_delayValue, SIGNAL(activated(int)), + SLOT(slotDelaySelected(int))); + + // Detect when the document colours are updated + connect(m_doc, SIGNAL(docColoursChanged()), + this, SLOT(slotDocColoursChanged())); + + // handle text changes for delay + connect(m_delayValue, SIGNAL(textChanged(const QString&)), + SLOT(slotDelayTextChanged(const QString &))); + + // set up combo box for colours + m_colourValue = new KComboBox(false, this); + m_colourValue->setFont(font); + //m_colourValue->setFixedHeight(comboHeight); + // m_colourValue->setMaximumWidth(width); + m_colourValue->setSizeLimit(20); + + // handle colour combo changes + connect(m_colourValue, SIGNAL(activated(int)), + SLOT(slotColourSelected(int))); + + // pre-set width of buttons so they don't grow later +// width = fontMetrics.width(i18n("used internally for spacing", "High: ----")); + + // highest playable note + // +// m_highButton = new QPushButton(i18n("High: ---"), this); +// QToolTip::add +// (m_highButton, i18n("Choose the highest suggested playable note, using a staff")); +// m_highButton->setFont(font); +// m_highButton->setMinimumWidth(width); + +// connect(m_highButton, SIGNAL(released()), +// SLOT(slotHighestPressed())); + + // lowest playable note + // +// m_lowButton = new QPushButton(i18n("Low: ----"), this); +// QToolTip::add +// (m_lowButton, i18n("Choose the lowest suggested playable note, using a staff")); +// m_lowButton->setFont(font); +// m_lowButton->setMinimumWidth(width); + +// connect(m_lowButton, SIGNAL(released()), +// SLOT(slotLowestPressed())); + + // Audio autofade enabled + // +// m_autoFadeBox = new QCheckBox(this); +// connect(m_autoFadeBox, SIGNAL(stateChanged(int)), +// this, SLOT(slotAudioFadeChanged(int))); + + // Fade in and out times + // +// m_fadeInSpin = new QSpinBox(this); +// m_fadeInSpin->setMinValue(0); +// m_fadeInSpin->setMaxValue(5000); +// m_fadeInSpin->setSuffix(i18n(" ms")); +// connect(m_fadeInSpin, SIGNAL(valueChanged(int)), +// this, SLOT(slotFadeInChanged(int))); + +// m_fadeOutSpin = new QSpinBox(this); +// m_fadeOutSpin->setMinValue(0); +// m_fadeOutSpin->setMaxValue(5000); +// m_fadeOutSpin->setSuffix(i18n(" ms")); +// connect(m_fadeOutSpin, SIGNAL(valueChanged(int)), +// this, SLOT(slotFadeOutChanged(int))); + + label->setFont(font); + repeatLabel->setFont(font); + quantizeLabel->setFont(font); + transposeLabel->setFont(font); + delayLabel->setFont(font); + colourLabel->setFont(font); +// m_autoFadeLabel->setFont(font); +// m_fadeInLabel->setFont(font); +// m_fadeOutLabel->setFont(font); +// m_rangeLabel->setFont(font); + + int row = 0; + +// gridLayout->addRowSpacing(0, 12); // why?? + + gridLayout->addWidget(label, row, 0); //, AlignRight); + gridLayout->addMultiCellWidget(m_label, row, row, 1, 4); //, AlignLeft); + gridLayout->addWidget(m_labelButton, row, 5); //, AlignLeft); + ++row; + + gridLayout->addWidget(repeatLabel, row, 0); //, AlignRight); + gridLayout->addWidget(m_repeatValue, row, 1); //, AlignLeft); + + gridLayout->addMultiCellWidget(transposeLabel, row, row, 2, 3, AlignRight); + gridLayout->addMultiCellWidget(m_transposeValue, row, row, 4, 5); + ++row; + + gridLayout->addWidget(quantizeLabel, row, 0); //, AlignRight); + gridLayout->addMultiCellWidget(m_quantizeValue, row, row, 1, 2); //, AlignLeft); + + gridLayout->addWidget(delayLabel, row, 3, AlignRight); + gridLayout->addMultiCellWidget(m_delayValue, row, row, 4, 5); + ++row; + + gridLayout->addWidget(colourLabel, row, 0); //, AlignRight); + gridLayout->addMultiCellWidget(m_colourValue, row, row, 1, 5); + ++row; + +// gridLayout->addWidget(m_rangeLabel, row, 0); //, AlignRight); +// gridLayout->addMultiCellWidget(m_lowButton, row, row, 1, 2); +// gridLayout->addMultiCellWidget(m_highButton, row, row, 3, 4); +// ++row; + +// m_autoFadeLabel->hide(); +// m_autoFadeBox->hide(); + /* + gridLayout->addWidget(m_fadeInLabel, 5, 0, AlignRight); + gridLayout->addWidget(m_fadeInSpin, 5, 1); + + gridLayout->addWidget(m_fadeOutLabel, 5, 2, AlignRight); + gridLayout->addWidget(m_fadeOutSpin, 5, 3); + */ + // Configure the empty final row to accomodate any extra vertical space. + + gridLayout->setRowStretch(gridLayout->numRows() - 1, 1); + + // Configure the empty final column to accomodate any extra horizontal + // space. + +// gridLayout->setColStretch(gridLayout->numCols() - 1, 1); + + // populate the quantize combo + // + QPixmap noMap = NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("menu-no-note")); + + for (unsigned int i = 0; i < m_standardQuantizations.size(); ++i) { + + timeT time = m_standardQuantizations[i]; + timeT error = 0; + QString label = NotationStrings::makeNoteMenuLabel(time, true, error); + QPixmap pmap = NotePixmapFactory::toQPixmap(NotePixmapFactory::makeNoteMenuPixmap(time, error)); + m_quantizeValue->insertItem(error ? noMap : pmap, label); + } + m_quantizeValue->insertItem(noMap, i18n("Off")); + + // default to last item + m_quantizeValue->setCurrentItem(m_quantizeValue->count() - 1); + + // populate the transpose combo + // + for (int i = -m_transposeRange; i < m_transposeRange + 1; i++) { + m_transposeValue->insertItem(noMap, QString("%1").arg(i)); + if (i == 0) + m_transposeValue->setCurrentItem(m_transposeValue->count() - 1); + } + + m_delays.clear(); + + for (int i = 0; i < 6; i++) { + timeT time = 0; + if (i > 0 && i < 6) { + time = Note(Note::Hemidemisemiquaver).getDuration() << (i - 1); + } else if (i > 5) { + time = Note(Note::Crotchet).getDuration() * (i - 4); + } + + m_delays.push_back(time); + + // check if it's a valid note duration (it will be for the + // time defn above, but if we were basing it on the sequencer + // resolution it might not be) & include a note pixmap if so + // + timeT error = 0; + QString label = NotationStrings::makeNoteMenuLabel(time, true, error); + QPixmap pmap = NotePixmapFactory::toQPixmap(NotePixmapFactory::makeNoteMenuPixmap(time, error)); + m_delayValue->insertItem((error ? noMap : pmap), label); + } + + for (int i = 0; i < 10; i++) { + int rtd = (i < 5 ? ((i + 1) * 10) : ((i - 3) * 50)); + m_realTimeDelays.push_back(rtd); + m_delayValue->insertItem(i18n("%1 ms").arg(rtd)); + } + + // set delay blank initially + m_delayValue->setCurrentItem( -1); + + // populate m_colourValue + slotDocColoursChanged(); + + //!!! disabled until after 1.3 +// m_highButton->hide(); +// m_lowButton->hide(); +// m_rangeLabel->hide(); + ////////////////////////////// + +} + +void +SegmentParameterBox::setDocument(RosegardenGUIDoc* doc) +{ + if (m_doc != 0) + disconnect(m_doc, SIGNAL(docColoursChanged()), + this, SLOT(slotDocColoursChanged())); + + m_doc = doc; + + // Detect when the document colours are updated + connect (m_doc, SIGNAL(docColoursChanged()), + this, SLOT(slotDocColoursChanged())); + + slotDocColoursChanged(); // repopulate combo +} + +void +SegmentParameterBox::useSegment(Segment *segment) +{ + m_segments.clear(); + m_segments.push_back(segment); + populateBoxFromSegments(); +} + +void +SegmentParameterBox::useSegments(const SegmentSelection &segments) +{ + m_segments.clear(); + + m_segments.resize(segments.size()); + std::copy(segments.begin(), segments.end(), m_segments.begin()); + + populateBoxFromSegments(); +} + +void +SegmentParameterBox::slotDocColoursChanged() +{ + RG_DEBUG << "SegmentParameterBox::slotDocColoursChanged()" << endl; + + m_colourValue->clear(); + m_colourList.clear(); + // Populate it from composition.m_segmentColourMap + ColourMap temp = m_doc->getComposition().getSegmentColourMap(); + + unsigned int i = 0; + + for (RCMap::const_iterator it = temp.begin(); it != temp.end(); ++it) { + QString qtrunc(strtoqstr(it->second.second)); + QPixmap colour(15, 15); + colour.fill(GUIPalette::convertColour(it->second.first)); + if (qtrunc == "") { + m_colourValue->insertItem(colour, i18n("Default"), i); + } else { + // truncate name to 15 characters to avoid the combo forcing the + // whole kit and kaboodle too wide + if (qtrunc.length() > 15) + qtrunc = qtrunc.left(12) + "..."; + m_colourValue->insertItem(colour, qtrunc, i); + } + m_colourList[it->first] = i; // maps colour number to menu index + ++i; + } + + m_addColourPos = i; + m_colourValue->insertItem(i18n("Add New Color"), m_addColourPos); + + m_colourValue->setCurrentItem(0); +} + +void SegmentParameterBox::update() +{ + RG_DEBUG << "SegmentParameterBox::update()" << endl; + + populateBoxFromSegments(); +} + +void +SegmentParameterBox::segmentRemoved(const Composition *composition, + Segment *segment) +{ + if (composition == &m_doc->getComposition()) { + + for (std::vector<Segment*>::iterator it = + m_segments.begin(); it != m_segments.end(); ++it) { + + if (*it == segment) { + m_segments.erase(it); + return ; + } + } + } +} + +void +SegmentParameterBox::populateBoxFromSegments() +{ + std::vector<Segment*>::iterator it; + Tristate repeated = NotApplicable; + Tristate quantized = NotApplicable; + Tristate transposed = NotApplicable; + Tristate delayed = NotApplicable; + Tristate diffcolours = NotApplicable; + Tristate highlow = NotApplicable; + unsigned int myCol = 0; + unsigned int myHigh = 127; + unsigned int myLow = 0; + + timeT qntzLevel = 0; + // At the moment we have no negative delay, so we use negative + // values to represent real-time delay in ms + timeT delayLevel = 0; + int transposeLevel = 0; + + if (m_segments.size() == 0) + m_label->setText(""); + else + m_label->setText(strtoqstr(m_segments[0]->getLabel())); + + for (it = m_segments.begin(); it != m_segments.end(); it++) { + // ok, first thing is we know we have at least one segment + if (repeated == NotApplicable) + repeated = None; + if (quantized == NotApplicable) + quantized = None; + if (transposed == NotApplicable) + transposed = None; + if (delayed == NotApplicable) + delayed = None; + if (diffcolours == NotApplicable) + diffcolours = None; + if (highlow == NotApplicable) + highlow = None; + + // Set label to "*" when multiple labels don't match + // + if (strtoqstr((*it)->getLabel()) != m_label->text()) + m_label->setText("*"); + + // Are all, some or none of the Segments repeating? + if ((*it)->isRepeating()) { + if (it == m_segments.begin()) + repeated = All; + else { + if (repeated == None) + repeated = Some; + } + } else { + if (repeated == All) + repeated = Some; + } + + // Quantization + // + if ((*it)->hasQuantization()) { + if (it == m_segments.begin()) { + quantized = All; + qntzLevel = (*it)->getQuantizer()->getUnit(); + } else { + // If quantize levels don't match + if (quantized == None || + (quantized == All && + qntzLevel != + (*it)->getQuantizer()->getUnit())) + quantized = Some; + } + } else { + if (quantized == All) + quantized = Some; + } + + // Transpose + // + if ((*it)->getTranspose() != 0) { + if (it == m_segments.begin()) { + transposed = All; + transposeLevel = (*it)->getTranspose(); + } else { + if (transposed == None || + (transposed == All && + transposeLevel != (*it)->getTranspose())) + transposed = Some; + } + + } else { + if (transposed == All) + transposed = Some; + } + + // Delay + // + timeT myDelay = (*it)->getDelay(); + if (myDelay == 0) { + myDelay = -((*it)->getRealTimeDelay().sec * 1000 + + (*it)->getRealTimeDelay().msec()); + } + + if (myDelay != 0) { + if (it == m_segments.begin()) { + delayed = All; + delayLevel = myDelay; + } else { + if (delayed == None || + (delayed == All && + delayLevel != myDelay)) + delayed = Some; + } + } else { + if (delayed == All) + delayed = Some; + } + + // Colour + + if (it == m_segments.begin()) { + myCol = (*it)->getColourIndex(); + } else { + if (myCol != (*it)->getColourIndex()) + ; + diffcolours = All; + } + + // Highest/Lowest playable + // + if (it == m_segments.begin()) { + myHigh = (*it)->getHighestPlayable(); + myLow = (*it)->getLowestPlayable(); + } else { + if (myHigh != (*it)->getHighestPlayable() || + myLow != (*it)->getLowestPlayable()) { + highlow = All; + } + } + + } + + switch (repeated) { + case All: + m_repeatValue->setChecked(true); + break; + + case Some: + m_repeatValue->setNoChange(); + break; + + case None: + case NotApplicable: + default: + m_repeatValue->setChecked(false); + break; + } + + m_repeatValue->setEnabled(repeated != NotApplicable); + + switch (quantized) { + case All: { + for (unsigned int i = 0; + i < m_standardQuantizations.size(); ++i) { + if (m_standardQuantizations[i] == qntzLevel) { + m_quantizeValue->setCurrentItem(i); + break; + } + } + } + break; + + case Some: + // Set the edit text to an unfeasible blank value meaning "Some" + // + m_quantizeValue->setCurrentItem( -1); + break; + + // Assuming "Off" is always the last field + case None: + default: + m_quantizeValue->setCurrentItem(m_quantizeValue->count() - 1); + break; + } + + m_quantizeValue->setEnabled(quantized != NotApplicable); + + switch (transposed) { + // setCurrentItem works with QStrings + // 2nd arg of "true" means "add if necessary" + case All: + m_transposeValue-> + setCurrentItem(QString("%1").arg(transposeLevel), true); + break; + + case Some: + m_transposeValue->setCurrentItem(QString(""), true); + break; + + case None: + default: + m_transposeValue->setCurrentItem("0"); + break; + } + + m_transposeValue->setEnabled(transposed != NotApplicable); + + m_delayValue->blockSignals(true); + + switch (delayed) { + case All: + if (delayLevel >= 0) { + timeT error = 0; + QString label = NotationStrings::makeNoteMenuLabel(delayLevel, + true, + error); + m_delayValue->setCurrentItem(label, true); + + } else if (delayLevel < 0) { + + m_delayValue->setCurrentItem(i18n("%1 ms").arg( -delayLevel), + true); + } + + break; + + case Some: + m_delayValue->setCurrentItem("", true); + break; + + case None: + default: + m_delayValue->setCurrentItem(0); + break; + } + + m_delayValue->setEnabled(delayed != NotApplicable); + + m_delayValue->blockSignals(false); + + switch (diffcolours) { + case None: + if (m_colourList.find(myCol) != m_colourList.end()) + m_colourValue->setCurrentItem(m_colourList[myCol]); + else + m_colourValue->setCurrentItem(0); + break; + + + case All: + case NotApplicable: + default: + m_colourValue->setCurrentItem(0); + break; + + } + + m_colourValue->setEnabled(diffcolours != NotApplicable); + + //!!! this is all borked up and useless; sort out after 1.3 +/* + switch (highlow) { + case All: + updateHighLow(); + break; + + case Some: + case None: + default: + m_highButton->setText(i18n("High: ---")); + m_lowButton->setText(i18n("Low: ----")); + highlow = NotApplicable; + break; + } + + m_highButton->setEnabled(highlow != NotApplicable); + m_lowButton->setEnabled(highlow != NotApplicable); +*/ + + // Enable or disable the fade in/out params +/* + if (m_segments.size() == 1 && + (*(m_segments.begin()))->getType() == Segment::Audio) { + m_autoFadeBox->blockSignals(true); + m_fadeInSpin->blockSignals(true); + m_fadeOutSpin->blockSignals(true); + + ... !!! No, not setting up autofade widgets. The implementation's too + incomplete to finish for this release. + + (Or for the next one after the one the previous comment referred to.) + + (Or for the one after the one after that. Will we ever get those + working, or should Rich's final legacy simply be quietly disappeared?) + + m_fadeInLabel->show(); + m_fadeInSpin->show(); + m_fadeOutLabel->show(); + m_fadeOutSpin->show(); + + instead: + + m_fadeInLabel->hide(); + m_fadeInSpin->hide(); + m_fadeOutLabel->hide(); + m_fadeOutSpin->hide(); + + m_autoFadeLabel->setEnabled(true); + m_autoFadeBox->setEnabled(true); + m_fadeInLabel->setEnabled(true); + m_fadeInSpin->setEnabled(true); + m_fadeOutLabel->setEnabled(true); + m_fadeOutSpin->setEnabled(true); + + Segment *seg = *(m_segments.begin()); + + int fadeInTime = seg->getFadeInTime().sec * 1000 + + seg->getFadeInTime().msec(); + m_fadeInSpin->setValue(fadeInTime); + + int fadeOutTime = seg->getFadeOutTime().sec * 1000 + + seg->getFadeOutTime().msec(); + m_fadeOutSpin->setValue(fadeOutTime); + + m_autoFadeBox->setChecked(seg->isAutoFading()); + + m_autoFadeBox->blockSignals(false); + m_fadeInSpin->blockSignals(false); + m_fadeOutSpin->blockSignals(false); + } else { + m_autoFadeLabel->setEnabled(false); + m_autoFadeBox->setEnabled(false); + m_fadeInLabel->setEnabled(false); + m_fadeInSpin->setEnabled(false); + m_fadeOutLabel->setEnabled(false); + m_fadeOutSpin->setEnabled(false); + + m_autoFadeLabel->hide(); + m_autoFadeBox->hide(); + m_fadeInLabel->hide(); + m_fadeInSpin->hide(); + m_fadeOutLabel->hide(); + m_fadeOutSpin->hide(); + + m_autoFadeBox->setChecked(false); + m_fadeInSpin->setValue(0); + m_fadeOutSpin->setValue(0); + } +*/ + +} + +void SegmentParameterBox::slotRepeatPressed() +{ + if (m_segments.size() == 0) + return ; + + bool state = false; + + switch (m_repeatValue->state()) { + case QButton::Off: + state = true; + break; + + case QButton::NoChange: + case QButton::On: + default: + state = false; + break; + } + + // update the check box and all current Segments + m_repeatValue->setChecked(state); + + addCommandToHistory(new SegmentCommandRepeat(m_segments, state)); + + // std::vector<Segment*>::iterator it; + + // for (it = m_segments.begin(); it != m_segments.end(); it++) + // (*it)->setRepeating(state); +} + +void +SegmentParameterBox::slotQuantizeSelected(int qLevel) +{ + bool off = (qLevel == m_quantizeValue->count() - 1); + + SegmentChangeQuantizationCommand *command = + new SegmentChangeQuantizationCommand + (off ? 0 : m_standardQuantizations[qLevel]); + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + command->addSegment(*it); + } + + addCommandToHistory(command); +} + +void +SegmentParameterBox::slotTransposeTextChanged(const QString &text) +{ + if (text.isEmpty() || m_segments.size() == 0) + return ; + + int transposeValue = text.toInt(); + + // addCommandToHistory(new SegmentCommandChangeTransposeValue(m_segments, + // transposeValue)); + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setTranspose(transposeValue); + } + + emit documentModified(); +} + +void +SegmentParameterBox::slotTransposeSelected(int value) +{ + slotTransposeTextChanged(m_transposeValue->text(value)); +} + +void +SegmentParameterBox::slotDelayTimeChanged(timeT delayValue) +{ + // by convention and as a nasty hack, we use negative timeT here + // to represent positive RealTime in ms + + if (delayValue > 0) { + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setDelay(delayValue); + (*it)->setRealTimeDelay(RealTime::zeroTime); + } + + } else if (delayValue < 0) { + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setDelay(0); + int sec = ( -delayValue) / 1000; + int nsec = (( -delayValue) - 1000 * sec) * 1000000; + (*it)->setRealTimeDelay(RealTime(sec, nsec)); + } + } else { + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setDelay(0); + (*it)->setRealTimeDelay(RealTime::zeroTime); + } + } + + emit documentModified(); +} + +void +SegmentParameterBox::slotDelayTextChanged(const QString &text) +{ + if (text.isEmpty() || m_segments.size() == 0) + return ; + + slotDelayTimeChanged( -(text.toInt())); +} + +void +SegmentParameterBox::slotDelaySelected(int value) +{ + if (value < int(m_delays.size())) { + slotDelayTimeChanged(m_delays[value]); + } else { + slotDelayTimeChanged( -(m_realTimeDelays[value - m_delays.size()])); + } +} + +void +SegmentParameterBox::slotColourSelected(int value) +{ + if (value != m_addColourPos) { + unsigned int temp = 0; + + ColourTable::ColourList::const_iterator pos; + for (pos = m_colourList.begin(); pos != m_colourList.end(); ++pos) { + if (pos->second == value) { + temp = pos->first; + break; + } + } + + SegmentSelection segments; + std::vector<Segment*>::iterator it; + + for (it = m_segments.begin(); it != m_segments.end(); ++it) { + segments.insert(*it); + } + + SegmentColourCommand *command = new SegmentColourCommand(segments, temp); + + addCommandToHistory(command); + } else { + ColourMap newMap = m_doc->getComposition().getSegmentColourMap(); + QColor newColour; + bool ok = false; + QString newName = KLineEditDlg::getText(i18n("New Color Name"), i18n("Enter new name"), + i18n("New"), &ok); + if ((ok == true) && (!newName.isEmpty())) { + KColorDialog box(this, "", true); + + int result = box.getColor(newColour); + + if (result == KColorDialog::Accepted) { + Colour newRColour = GUIPalette::convertColour(newColour); + newMap.addItem(newRColour, qstrtostr(newName)); + SegmentColourMapCommand *command = new SegmentColourMapCommand(m_doc, newMap); + addCommandToHistory(command); + slotDocColoursChanged(); + } + } + // Else we don't do anything as they either didn't give a name· + // or didn't give a colour + } + + +} + +void +SegmentParameterBox::updateHighLow() +{ + // Key of C major and NoAccidental means any "black key" notes will be + // written as sharps. + Accidental accidental = Accidentals::NoAccidental; + Rosegarden::Key key = Rosegarden::Key("C major"); + + Pitch highest(m_highestPlayable, accidental); + Pitch lowest(m_lowestPlayable, accidental); + + KConfig *config = kapp->config(); + config->setGroup(GeneralOptionsConfigGroup); + int base = config->readNumEntry("midipitchoctave", -2); + //!!! FIXME this code is broken, and needs to be fixed after the fashion of + //the TPB, but I'm not bothering with that at this time, because they are + //going to be hidden for 1.3 anyway +// m_highButton->setText(QString("&High: %1%2").arg(highest.getNoteName(key)).arg(highest.getOctave(base))); +// m_lowButton->setText(QString("&Low: %1%2").arg(lowest.getNoteName(key)).arg(lowest.getOctave(base))); +} + +void +SegmentParameterBox::slotHighestPressed() +{ + RG_DEBUG << "SegmentParameterBox::slotHighestPressed()" << endl; + + PitchPickerDialog dialog(0, m_highestPlayable, i18n("Highest playable note")); + std::vector<Segment*>::iterator it; + + if (dialog.exec() == QDialog::Accepted) { + m_highestPlayable = dialog.getPitch(); + updateHighLow(); + + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setHighestPlayable(m_highestPlayable); + } + + emit documentModified(); + } +} + +void +SegmentParameterBox::slotLowestPressed() +{ + RG_DEBUG << "SegmentParameterBox::slotLowestPressed()" << endl; + + PitchPickerDialog dialog(0, m_lowestPlayable, i18n("Lowest playable note")); + std::vector<Segment*>::iterator it; + + if (dialog.exec() == QDialog::Accepted) { + m_lowestPlayable = dialog.getPitch(); + updateHighLow(); + + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setLowestPlayable(m_lowestPlayable); + } + + emit documentModified(); + } +} + +MultiViewCommandHistory* +SegmentParameterBox::getCommandHistory() +{ + return m_doc->getCommandHistory(); +} + +void +SegmentParameterBox::addCommandToHistory(KCommand *command) +{ + m_doc->getCommandHistory()->addCommand(command); +} + +void +SegmentParameterBox::slotEditSegmentLabel() +{ + QString editLabel; + + if (m_segments.size() == 0) + return ; + else if (m_segments.size() == 1) + editLabel = i18n("Modify Segment label"); + else + editLabel = i18n("Modify Segments label"); + + bool ok = false; + + // Remove the asterisk if we're using it + // + QString label = m_label->text(); + if (label == "*") + label = ""; + + QString newLabel = KLineEditDlg::getText(editLabel, + i18n("Enter new label"), + m_label->text(), + &ok, + this); + + if (ok) { + SegmentSelection segments; + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); ++it) + segments.insert(*it); + + SegmentLabelCommand *command = new + SegmentLabelCommand(segments, newLabel); + + addCommandToHistory(command); + + // fix #1776915, maybe? + update(); + } +} + +void +SegmentParameterBox::slotAudioFadeChanged(int value) +{ + RG_DEBUG << "SegmentParameterBox::slotAudioFadeChanged - value = " + << value << endl; +/* + if (m_segments.size() == 0) + return ; + + bool state = false; + if (value == QButton::On) + state = true; + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setAutoFade(state); + } +*/ +} + +void +SegmentParameterBox::slotFadeInChanged(int value) +{ + RG_DEBUG << "SegmentParameterBox::slotFadeInChanged - value = " + << value << endl; +/* + if (m_segments.size() == 0) + return ; + + if (value == 0 && m_fadeOutSpin->value() == 0) + slotAudioFadeChanged(QButton::Off); + else + slotAudioFadeChanged(QButton::On); + + // Convert from ms + // + RealTime fadeInTime(value / 1000, (value % 1000) * 1000000); + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setFadeInTime(fadeInTime); + } + + emit documentModified(); +*/ +} + +void +SegmentParameterBox::slotFadeOutChanged(int value) +{ + RG_DEBUG << "SegmentParameterBox::slotFadeOutChanged - value = " + << value << endl; +/* + if (m_segments.size() == 0) + return ; + + if (value == 0 && m_fadeInSpin->value() == 0) + slotAudioFadeChanged(QButton::Off); + else + slotAudioFadeChanged(QButton::On); + + // Convert from ms + // + RealTime fadeOutTime(value / 1000000, (value % 1000) * 10000000); + + std::vector<Segment*>::iterator it; + for (it = m_segments.begin(); it != m_segments.end(); it++) { + (*it)->setFadeOutTime(fadeOutTime); + } + + emit documentModified(); +*/ +} + +void +SegmentParameterBox::showAdditionalControls(bool showThem) +{ + //!!! disabled until after 1.3 + /* m_highButton->setShown(showThem); + m_lowButton->setShown(showThem); + m_rangeLabel->setShown(showThem); */ +} + +QString +SegmentParameterBox::getPreviousBox(RosegardenParameterArea::Arrangement arrangement) const +{ + if (arrangement == RosegardenParameterArea::CLASSIC_STYLE) { + return ""; + } else { + return i18n("Instrument"); + } +} + +} +#include "SegmentParameterBox.moc" diff --git a/src/gui/editors/parameters/SegmentParameterBox.h b/src/gui/editors/parameters/SegmentParameterBox.h new file mode 100644 index 0000000..a8b0353 --- /dev/null +++ b/src/gui/editors/parameters/SegmentParameterBox.h @@ -0,0 +1,174 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_SEGMENTPARAMETERBOX_H_ +#define _RG_SEGMENTPARAMETERBOX_H_ + +#include "base/Composition.h" +#include "base/MidiProgram.h" +#include "gui/widgets/ColourTable.h" +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include <qstring.h> +#include <vector> +#include "base/Event.h" + + +class QWidget; +class QSpinBox; +class QPushButton; +class QLabel; +class QCheckBox; +class KCommand; +class KComboBox; + + +namespace Rosegarden +{ + +class TristateCheckBox; +class SegmentSelection; +class Segment; +class RosegardenGUIDoc; +class MultiViewCommandHistory; +class Composition; + + +class SegmentParameterBox : public RosegardenParameterBox, + public CompositionObserver +{ +Q_OBJECT + +public: + + typedef enum + { + None, + Some, + All, + NotApplicable // no applicable segments selected + } Tristate; + + SegmentParameterBox(RosegardenGUIDoc *doc, + QWidget *parent=0); + ~SegmentParameterBox(); + + // Use Segments to update GUI parameters + // + void useSegment(Segment *segment); + void useSegments(const SegmentSelection &segments); + + // Command history stuff + MultiViewCommandHistory* getCommandHistory(); + void addCommandToHistory(KCommand *command); + + void setDocument(RosegardenGUIDoc*); + + // CompositionObserver interface + // + virtual void segmentRemoved(const Composition *, + Segment *); + + virtual void showAdditionalControls(bool showThem); + + virtual QString getPreviousBox(RosegardenParameterArea::Arrangement) const; + +public slots: + void slotRepeatPressed(); + void slotQuantizeSelected(int); + + void slotTransposeSelected(int); + void slotTransposeTextChanged(const QString &); + + void slotDelaySelected(int); + void slotDelayTimeChanged(timeT delayValue); + void slotDelayTextChanged(const QString &); + + void slotEditSegmentLabel(); + + void slotColourSelected(int); + void slotDocColoursChanged(); + + void slotAudioFadeChanged(int); + void slotFadeInChanged(int); + void slotFadeOutChanged(int); + + void slotHighestPressed(); + void slotLowestPressed(); + + virtual void update(); + +signals: + void documentModified(); + void canvasModified(); + +protected: + void initBox(); + void populateBoxFromSegments(); + void updateHighLow(); + + QLabel *m_label; +// QLabel *m_rangeLabel; + QPushButton *m_labelButton; +// QPushButton *m_highButton; +// QPushButton *m_lowButton; + TristateCheckBox *m_repeatValue; + KComboBox *m_quantizeValue; + KComboBox *m_transposeValue; + KComboBox *m_delayValue; + KComboBox *m_colourValue; + + // Audio autofade + // +// QLabel *m_autoFadeLabel; +// QCheckBox *m_autoFadeBox; +// QLabel *m_fadeInLabel; +// QSpinBox *m_fadeInSpin; +// QLabel *m_fadeOutLabel; +// QSpinBox *m_fadeOutSpin; + + int m_addColourPos; + + // used to keep track of highest/lowest as there is no associated spinbox + // to query for its value + int m_highestPlayable; + int m_lowestPlayable; + + std::vector<Segment*> m_segments; + std::vector<timeT> m_standardQuantizations; + std::vector<timeT> m_delays; + std::vector<int> m_realTimeDelays; + ColourTable::ColourList m_colourList; + + RosegardenGUIDoc *m_doc; + + MidiByte m_transposeRange; +}; + + + +} + +#endif diff --git a/src/gui/editors/parameters/TrackParameterBox.cpp b/src/gui/editors/parameters/TrackParameterBox.cpp new file mode 100644 index 0000000..fc85346 --- /dev/null +++ b/src/gui/editors/parameters/TrackParameterBox.cpp @@ -0,0 +1,1022 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + This file is Copyright 2006 + Pedro Lopez-Cabanillas <[email protected]> + D. Michael McIntyre <[email protected]> + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "TrackParameterBox.h" +#include <qlayout.h> +#include <kapplication.h> + +#include <klocale.h> +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "gui/general/ClefIndex.h" +#include "document/ConfigGroups.h" +#include "base/AudioPluginInstance.h" +#include "base/Colour.h" +#include "base/ColourMap.h" +#include "base/Composition.h" +#include "base/Device.h" +#include "base/Exception.h" +#include "base/Instrument.h" +#include "base/MidiDevice.h" +#include "base/MidiProgram.h" +#include "base/NotationTypes.h" +#include "base/Studio.h" +#include "base/Track.h" +#include "base/StaffExportTypes.h" +#include "commands/segment/SegmentSyncCommand.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/dialogs/PitchPickerDialog.h" +#include "gui/general/GUIPalette.h" +#include "gui/general/PresetHandlerDialog.h" +#include "gui/widgets/CollapsingFrame.h" +#include "gui/widgets/ColourTable.h" +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include "sound/PluginIdentifier.h" +#include <kcolordialog.h> +#include <kcombobox.h> +#include <kconfig.h> +#include <klineeditdlg.h> +#include <kmessagebox.h> +#include <ksqueezedtextlabel.h> +#include <ktabwidget.h> +#include <qcolor.h> +#include <qdialog.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qframe.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qregexp.h> +#include <qscrollview.h> +#include <qstring.h> +#include <qtooltip.h> +#include <qvbox.h> +#include <qwidget.h> +#include <qwidgetstack.h> +#include <qcheckbox.h> + + +namespace Rosegarden +{ + +TrackParameterBox::TrackParameterBox( RosegardenGUIDoc *doc, + QWidget *parent) + : RosegardenParameterBox(i18n("Track"), + i18n("Track Parameters"), + parent), + m_doc(doc), + m_highestPlayable(127), + m_lowestPlayable(0), + m_selectedTrackId( -1) +{ + QFont font(m_font); + QFont title_font(m_font); + QFontMetrics metrics(font); + int width11 = metrics.width("12345678901"); + int width20 = metrics.width("12345678901234567890"); + int width22 = metrics.width("1234567890123456789012"); + int width25 = metrics.width("1234567890123456789012345"); + setFont(m_font); + title_font.setBold(true); + + // Set up default expansions for the collapsing elements + KConfig *config = kapp->config(); + QString groupTemp = config->group(); + config->setGroup("CollapsingFrame"); + bool expanded = config->readBoolEntry("trackparametersplayback", true); + config->writeEntry("trackparametersplayback", expanded); + expanded = config->readBoolEntry("trackparametersrecord", false); + config->writeEntry("trackparametersrecord", expanded); + expanded = config->readBoolEntry("trackparametersdefaults", false); + config->writeEntry("trackparametersdefaults", expanded); + expanded = config->readBoolEntry("trackstaffgroup", false); + config->writeEntry("trackstaffgroup", expanded); + config->setGroup(groupTemp); + + QGridLayout *mainLayout = new QGridLayout(this, 5, 1, 2, 1); + + int row = 0; + + // track label + // + m_trackLabel = new KSqueezedTextLabel(i18n("<untitled>"), this); + m_trackLabel->setAlignment(Qt::AlignCenter); + //mainLayout->addMultiCellWidget(m_trackLabel, 0, 0, 0, 5, AlignCenter); + mainLayout->addWidget(m_trackLabel, 0, 0); + + // playback group + // + CollapsingFrame *cframe = new CollapsingFrame(i18n("Playback parameters"), + this, "trackparametersplayback"); + m_playbackGroup = new QFrame(cframe); + cframe->setWidget(m_playbackGroup); + QGridLayout *groupLayout = new QGridLayout(m_playbackGroup, 3, 3, 3, 2); + + // playback group title + // + row = 0; + + // playback device + // + // row++; + QLabel *devLabel = new QLabel(i18n("Device"), m_playbackGroup); + groupLayout->addWidget(devLabel, row, 0); + m_playDevice = new KComboBox(m_playbackGroup); + m_playDevice->setMinimumWidth(width25); + groupLayout->addMultiCellWidget(m_playDevice, row, row, 1, 2); + + // playback instrument + // + row++; + QLabel *insLabel = new QLabel(i18n("Instrument"), m_playbackGroup); + groupLayout->addMultiCellWidget(insLabel, row, row, 0, 1); + m_instrument = new KComboBox(m_playbackGroup); + m_instrument->setSizeLimit( 16 ); + m_instrument->setMinimumWidth(width22); + groupLayout->addWidget(m_instrument, row, 2); + + groupLayout->setColStretch(groupLayout->numCols() - 1, 1); + + mainLayout->addWidget(cframe, 1, 0); + + // record group + // + cframe = new CollapsingFrame(i18n("Recording filters"), this, + "trackparametersrecord"); + m_recordGroup = new QFrame(cframe); + cframe->setWidget(m_recordGroup); + groupLayout = new QGridLayout(m_recordGroup, 3, 3, 3, 2); + + // recording group title + // + row = 0; + + // recording device + groupLayout->addWidget(new QLabel(i18n("Device"), m_recordGroup), row, 0); + m_recDevice = new KComboBox(m_recordGroup); + m_recDevice->setMinimumWidth(width25); + groupLayout->addMultiCellWidget(m_recDevice, row, row, 1, 2); + + // recording channel + // + row++; + groupLayout->addMultiCellWidget(new QLabel(i18n("Channel"), m_recordGroup), row, row, 0, 1); + m_recChannel = new KComboBox(m_recordGroup); + m_recChannel->setSizeLimit( 17 ); + m_recChannel->setMinimumWidth(width11); + groupLayout->addWidget(m_recChannel, row, 2); + + groupLayout->setColStretch(groupLayout->numCols() - 1, 1); + + mainLayout->addWidget(cframe, 2, 0); + + // staff group + // + cframe = new CollapsingFrame(i18n("Staff export options"), this, + "staffoptions"); + m_staffGroup = new QFrame(cframe); + cframe->setWidget(m_staffGroup); + groupLayout = new QGridLayout(m_staffGroup, 2, 2, 2, 2); + + groupLayout->setColStretch(1, 1); + + row = 0; + + // Notation size (export only) + // + // NOTE: This is the only way to get a \small or \tiny inserted before the + // first note in LilyPond export. Setting the actual staff size on a + // per-staff (rather than per-score) basis is something the author of the + // LilyPond documentation has no idea how to do, so we settle for this, + // which is not as nice, but actually a lot easier to implement. + m_staffGrpLbl = new QLabel(i18n("Notation size:"), m_staffGroup); + groupLayout->addWidget(m_staffGrpLbl, row, 0, AlignLeft); + m_staffSizeCombo = new KComboBox(m_staffGroup); + m_staffSizeCombo->setMinimumWidth(width11); + m_staffSizeCombo->insertItem(i18n("Normal"), StaffTypes::Normal); + m_staffSizeCombo->insertItem(i18n("Small"), StaffTypes::Small); + m_staffSizeCombo->insertItem(i18n("Tiny"), StaffTypes::Tiny); + + groupLayout->addMultiCellWidget(m_staffSizeCombo, row, row, 1, 2); + + // Staff bracketing (export only at the moment, but using this for GUI + // rendering would be nice in the future!) //!!! + row++; + m_grandStaffLbl = new QLabel(i18n("Bracket type:"), m_staffGroup); + groupLayout->addWidget(m_grandStaffLbl, row, 0, AlignLeft); + m_staffBracketCombo = new KComboBox(m_staffGroup); + m_staffBracketCombo->setMinimumWidth(width11); + m_staffBracketCombo->insertItem(i18n("-----"), Brackets::None); + m_staffBracketCombo->insertItem(i18n("[----"), Brackets::SquareOn); + m_staffBracketCombo->insertItem(i18n("----]"), Brackets::SquareOff); + m_staffBracketCombo->insertItem(i18n("[---]"), Brackets::SquareOnOff); + m_staffBracketCombo->insertItem(i18n("{----"), Brackets::CurlyOn); + m_staffBracketCombo->insertItem(i18n("----}"), Brackets::CurlyOff); + m_staffBracketCombo->insertItem(i18n("{[---"), Brackets::CurlySquareOn); + m_staffBracketCombo->insertItem(i18n("---]}"), Brackets::CurlySquareOff); + + groupLayout->addMultiCellWidget(m_staffBracketCombo, row, row, 1, 2); + + mainLayout->addWidget(cframe, 3, 0); + + + // default segment group + // + cframe = new CollapsingFrame(i18n("Create segments with"), this, + "trackparametersdefaults"); + m_defaultsGroup = new QFrame(cframe); + cframe->setWidget(m_defaultsGroup); + groupLayout = new QGridLayout(m_defaultsGroup, 6, 6, 3, 2); + + groupLayout->setColStretch(1, 1); + + row = 0; + + // preset picker + m_psetLbl = new QLabel(i18n("Preset"), m_defaultsGroup); + groupLayout->addWidget(m_psetLbl, row, 0, AlignLeft); + + m_presetLbl = new QLabel(i18n("<none>"), m_defaultsGroup); + m_presetLbl->setFrameStyle(QFrame::Panel | QFrame::Sunken); + m_presetLbl->setFixedWidth(width20); + groupLayout->addMultiCellWidget(m_presetLbl, row, row, 1, 3); + + m_presetButton = new QPushButton(i18n("Load"), m_defaultsGroup); + groupLayout->addMultiCellWidget(m_presetButton, row, row, 4, 5); + + // default clef + // + row++; + m_clefLbl = new QLabel(i18n("Clef"), m_defaultsGroup); + groupLayout->addWidget(m_clefLbl, row, 0, AlignLeft); + m_defClef = new KComboBox(m_defaultsGroup); + m_defClef->setMinimumWidth(width11); + m_defClef->insertItem(i18n("treble"), TrebleClef); + m_defClef->insertItem(i18n("bass"), BassClef); + m_defClef->insertItem(i18n("crotales"), CrotalesClef); + m_defClef->insertItem(i18n("xylophone"), XylophoneClef); + m_defClef->insertItem(i18n("guitar"), GuitarClef); + m_defClef->insertItem(i18n("contrabass"), ContrabassClef); + m_defClef->insertItem(i18n("celesta"), CelestaClef); + m_defClef->insertItem(i18n("old celesta"), OldCelestaClef); + m_defClef->insertItem(i18n("french"), FrenchClef); + m_defClef->insertItem(i18n("soprano"), SopranoClef); + m_defClef->insertItem(i18n("mezzosoprano"), MezzosopranoClef); + m_defClef->insertItem(i18n("alto"), AltoClef); + m_defClef->insertItem(i18n("tenor"), TenorClef); + m_defClef->insertItem(i18n("baritone"), BaritoneClef); + m_defClef->insertItem(i18n("varbaritone"), VarbaritoneClef); + m_defClef->insertItem(i18n("subbass"), SubbassClef); + /* clef types in the datbase that are not yet supported must be ignored for + * now: + m_defClef->insertItem(i18n("two bar"), TwoBarClef); */ + groupLayout->addMultiCellWidget(m_defClef, row, row, 1, 2); + + // default transpose + // + m_transpLbl = new QLabel(i18n("Transpose"), m_defaultsGroup); + groupLayout->addMultiCellWidget(m_transpLbl, row, row, 3, 4, AlignRight); + m_defTranspose = new KComboBox(m_defaultsGroup); + + connect(m_defTranspose, SIGNAL(activated(int)), + SLOT(slotTransposeIndexChanged(int))); + + int transposeRange = 48; + for (int i = -transposeRange; i < transposeRange + 1; i++) { + m_defTranspose->insertItem(QString("%1").arg(i)); + if (i == 0) + m_defTranspose->setCurrentItem(m_defTranspose->count() - 1); + } + + groupLayout->addMultiCellWidget(m_defTranspose, row, row, 5, 5); + + // highest/lowest playable note + // + row++; + m_rangeLbl = new QLabel(i18n("Pitch"), m_defaultsGroup); + groupLayout->addMultiCellWidget(m_rangeLbl, row, row, 0, 0); + + groupLayout->addWidget(new QLabel(i18n("Lowest"), m_defaultsGroup), row, 1, AlignRight); + + m_lowButton = new QPushButton(i18n("---"), m_defaultsGroup); + QToolTip::add + (m_lowButton, i18n("Choose the lowest suggested playable note, using a staff")); + groupLayout->addMultiCellWidget(m_lowButton, row, row, 2, 2); + + groupLayout->addWidget(new QLabel(i18n("Highest"), m_defaultsGroup), row, 3, AlignRight); + + m_highButton = new QPushButton(i18n("---"), m_defaultsGroup); + QToolTip::add + (m_highButton, i18n("Choose the highest suggested playable note, using a staff")); + groupLayout->addMultiCellWidget(m_highButton, row, row, 4, 5); + + updateHighLow(); + + // default color + // + row++; + m_colorLbl = new QLabel(i18n("Color"), m_defaultsGroup); + groupLayout->addWidget(m_colorLbl, row, 0, AlignLeft); + m_defColor = new KComboBox(false, m_defaultsGroup); + m_defColor->setSizeLimit(20); + groupLayout->addMultiCellWidget(m_defColor, row, row, 1, 5); + + // populate combo from doc colors + slotDocColoursChanged(); + + mainLayout->addWidget(cframe, 4, 0); + + + // Configure the empty final row to accomodate any extra vertical space. + // +// mainLayout->setColStretch(mainLayout->numCols() - 1, 1); + mainLayout->setRowStretch(mainLayout->numRows() - 1, 1); + + // Connections + connect( m_playDevice, SIGNAL(activated(int)), + this, SLOT(slotPlaybackDeviceChanged(int))); + + connect( m_instrument, SIGNAL(activated(int)), + this, SLOT(slotInstrumentChanged(int))); + + connect( m_recDevice, SIGNAL(activated(int)), + this, SLOT(slotRecordingDeviceChanged(int))); + + connect( m_recChannel, SIGNAL(activated(int)), + this, SLOT(slotRecordingChannelChanged(int))); + + connect( m_defClef, SIGNAL(activated(int)), + this, SLOT(slotClefChanged(int))); + + // Detect when the document colours are updated + connect(m_doc, SIGNAL(docColoursChanged()), + this, SLOT(slotDocColoursChanged())); + + // handle colour combo changes + connect(m_defColor, SIGNAL(activated(int)), + SLOT(slotColorChanged(int))); + + connect(m_highButton, SIGNAL(released()), + SLOT(slotHighestPressed())); + + connect(m_lowButton, SIGNAL(released()), + SLOT(slotLowestPressed())); + + connect(m_presetButton, SIGNAL(released()), + SLOT(slotPresetPressed())); + + connect(m_staffSizeCombo, SIGNAL(activated(int)), + this, SLOT(slotStaffSizeChanged(int))); + + connect(m_staffBracketCombo, SIGNAL(activated(int)), + this, SLOT(slotStaffBracketChanged(int))); +} + +TrackParameterBox::~TrackParameterBox() +{} + +void + +TrackParameterBox::setDocument( RosegardenGUIDoc *doc ) +{ + if (m_doc != doc) { + RG_DEBUG << "TrackParameterBox::setDocument\n"; + m_doc = doc; + populateDeviceLists(); + } +} + +void +TrackParameterBox::populateDeviceLists() +{ + RG_DEBUG << "TrackParameterBox::populateDeviceLists()\n"; + populatePlaybackDeviceList(); + //populateRecordingDeviceList(); + slotUpdateControls( -1); + m_lastInstrumentType = -1; +} + +void +TrackParameterBox::populatePlaybackDeviceList() +{ + RG_DEBUG << "TrackParameterBox::populatePlaybackDeviceList()\n"; + m_playDevice->clear(); + m_playDeviceIds.clear(); + m_instrument->clear(); + m_instrumentIds.clear(); + m_instrumentNames.clear(); + + Studio &studio = m_doc->getStudio(); + + // Get the list + InstrumentList list = studio.getPresentationInstruments(); + InstrumentList::iterator it; + int currentDevId = -1; + + for (it = list.begin(); it != list.end(); it++) { + + if (! (*it)) + continue; // sanity check + + //QString iname(strtoqstr((*it)->getPresentationName())); + QString iname(strtoqstr((*it)->getName())); + QString pname(strtoqstr((*it)->getProgramName())); + Device *device = (*it)->getDevice(); + DeviceId devId = device->getId(); + + if ((*it)->getType() == Instrument::SoftSynth) { + iname.replace("Synth plugin ", ""); + pname = ""; + AudioPluginInstance *plugin = (*it)->getPlugin + (Instrument::SYNTH_PLUGIN_POSITION); + if (plugin) { + pname = strtoqstr(plugin->getProgram()); + QString identifier = strtoqstr(plugin->getIdentifier()); + if (identifier != "") { + QString type, soName, label; + PluginIdentifier::parseIdentifier + (identifier, type, soName, label); + if (pname == "") { + pname = strtoqstr(plugin->getDistinctiveConfigurationText()); + } + if (pname != "") { + pname = QString("%1: %2").arg(label).arg(pname); + } else { + pname = label; + } + } + } + } + + if (devId != (DeviceId)(currentDevId)) { + currentDevId = int(devId); + QString deviceName = strtoqstr(device->getName()); + m_playDevice->insertItem(deviceName); + m_playDeviceIds.push_back(currentDevId); + } + + if (pname != "") + iname += " (" + pname + ")"; + m_instrumentIds[currentDevId].push_back((*it)->getId()); + m_instrumentNames[currentDevId].append(iname); + + } + + m_playDevice->setCurrentItem( -1); + m_instrument->setCurrentItem( -1); +} + +void +TrackParameterBox::populateRecordingDeviceList() +{ + RG_DEBUG << "TrackParameterBox::populateRecordingDeviceList()\n"; + + if (m_selectedTrackId < 0) + return ; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + if (!trk) + return ; + + Instrument *inst = m_doc->getStudio().getInstrumentById(trk->getInstrument()); + if (!inst) + return ; + + if (m_lastInstrumentType != (char)inst->getInstrumentType()) { + m_lastInstrumentType = (char)inst->getInstrumentType(); + + m_recDevice->clear(); + m_recDeviceIds.clear(); + m_recChannel->clear(); + + if (inst->getInstrumentType() == Instrument::Audio) { + + m_recDeviceIds.push_back(Device::NO_DEVICE); + m_recDevice->insertItem(i18n("Audio")); + m_recChannel->insertItem(i18n("Audio")); + + m_recDevice->setEnabled(false); + m_recChannel->setEnabled(false); + + // hide these for audio instruments + m_defaultsGroup->parentWidget()->setShown(false); + + } else { // InstrumentType::Midi and InstrumentType::SoftSynth + + // show these if not audio instrument + m_defaultsGroup->parentWidget()->setShown(true); + + m_recDeviceIds.push_back(Device::ALL_DEVICES); + m_recDevice->insertItem(i18n("All")); + + DeviceList *devices = m_doc->getStudio().getDevices(); + DeviceListConstIterator it; + for (it = devices->begin(); it != devices->end(); it++) { + MidiDevice *dev = + dynamic_cast<MidiDevice*>(*it); + if (dev) { + if (dev->getDirection() == MidiDevice::Record + && dev->isRecording()) { + QString connection = strtoqstr(dev->getConnection()); + // remove trailing "(duplex)", "(read only)", "(write only)" etc + connection.replace(QRegExp("\\s*\\([^)0-9]+\\)\\s*$"), ""); + m_recDevice->insertItem(connection); + m_recDeviceIds.push_back(dev->getId()); + } + } + } + + m_recChannel->insertItem(i18n("All")); + for (int i = 1; i < 17; ++i) { + m_recChannel->insertItem(QString::number(i)); + } + + m_recDevice->setEnabled(true); + m_recChannel->setEnabled(true); + } + } + + if (inst->getInstrumentType() == Instrument::Audio) { + m_recDevice->setCurrentItem(0); + m_recChannel->setCurrentItem(0); + } else { + m_recDevice->setCurrentItem(0); + m_recChannel->setCurrentItem((int)trk->getMidiInputChannel() + 1); + for (unsigned int i = 0; i < m_recDeviceIds.size(); ++i) { + if (m_recDeviceIds[i] == trk->getMidiInputDevice()) { + m_recDevice->setCurrentItem(i); + break; + } + } + } +} + +void +TrackParameterBox::updateHighLow() +{ + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + + trk->setHighestPlayable(m_highestPlayable); + trk->setLowestPlayable(m_lowestPlayable); + + Accidental accidental = Accidentals::NoAccidental; + + Pitch highest(m_highestPlayable, accidental); + Pitch lowest(m_lowestPlayable, accidental); + + KConfig *config = kapp->config(); + config->setGroup(GeneralOptionsConfigGroup); + int base = config->readNumEntry("midipitchoctave", -2); + bool useSharps = true; + bool includeOctave = true; + +// m_highButton->setText(i18n("High: %1").arg(highest.getAsString(useSharps, includeOctave, base))); +// m_lowButton->setText(i18n("Low: %1").arg(lowest.getAsString(useSharps, includeOctave, base))); + m_highButton->setText(QString("%1").arg(highest.getAsString(useSharps, includeOctave, base))); + m_lowButton->setText(QString("%1").arg(lowest.getAsString(useSharps, includeOctave, base))); + + m_presetLbl->setEnabled(false); +} + +void +TrackParameterBox::slotUpdateControls(int /*dummy*/) +{ + RG_DEBUG << "TrackParameterBox::slotUpdateControls()\n"; + slotPlaybackDeviceChanged( -1); + slotInstrumentChanged( -1); + + if (m_selectedTrackId < 0) + return ; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + if (!trk) + return ; + + m_defClef->setCurrentItem(trk->getClef()); + m_defTranspose->setCurrentItem(QString("%1").arg(trk->getTranspose()), true); + m_defColor->setCurrentItem(trk->getColor()); + m_highestPlayable = trk->getHighestPlayable(); + m_lowestPlayable = trk->getLowestPlayable(); + updateHighLow(); + // set this down here because updateHighLow just disabled the label + m_presetLbl->setText(trk->getPresetLabel()); + m_presetLbl->setEnabled(true); + + m_staffSizeCombo->setCurrentItem(trk->getStaffSize()); + m_staffBracketCombo->setCurrentItem(trk->getStaffBracket()); +} + +void +TrackParameterBox::slotSelectedTrackChanged() +{ + RG_DEBUG << "TrackParameterBox::slotSelectedTrackChanged()\n"; + Composition &comp = m_doc->getComposition(); + TrackId newTrack = comp.getSelectedTrack(); + if ( newTrack != m_selectedTrackId ) { + m_presetLbl->setEnabled(true); + m_selectedTrackId = newTrack; + slotSelectedTrackNameChanged(); + slotUpdateControls( -1); + } +} + +void +TrackParameterBox::slotSelectedTrackNameChanged() +{ + RG_DEBUG << "TrackParameterBox::sotSelectedTrackNameChanged()\n"; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + QString m_trackName = trk->getLabel(); + if (m_trackName.isEmpty()) + m_trackName = i18n("<untitled>"); + else + m_trackName.truncate(20); + int trackNum = trk->getPosition() + 1; + m_trackLabel->setText(i18n("[ Track %1 - %2 ]").arg(trackNum).arg(m_trackName)); +} + +void +TrackParameterBox::slotPlaybackDeviceChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::slotPlaybackDeviceChanged(" << index << ")\n"; + DeviceId devId; + if (index == -1) { + if (m_selectedTrackId < 0) + return ; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + if (!trk) + return ; + Instrument *inst = m_doc->getStudio().getInstrumentById(trk->getInstrument()); + if (!inst) + return ; + devId = inst->getDevice()->getId(); + int pos = -1; + IdsVector::const_iterator it; + for ( it = m_playDeviceIds.begin(); it != m_playDeviceIds.end(); ++it) { + pos++; + if ((*it) == devId) + break; + } + m_playDevice->setCurrentItem(pos); + } else { + devId = m_playDeviceIds[index]; + } + + m_instrument->clear(); + m_instrument->insertStringList(m_instrumentNames[devId]); + + populateRecordingDeviceList(); + + if (index != -1) { + m_instrument->setCurrentItem(0); + slotInstrumentChanged(0); + } +} + +void +TrackParameterBox::slotInstrumentChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::slotInstrumentChanged(" << index << ")\n"; + DeviceId devId; + Instrument *inst; + if (index == -1) { + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + inst = m_doc->getStudio().getInstrumentById(trk->getInstrument()); + if (!inst) + return ; + devId = inst->getDevice()->getId(); + + int pos = -1; + IdsVector::const_iterator it; + for ( it = m_instrumentIds[devId].begin(); it != m_instrumentIds[devId].end(); ++it ) { + pos++; + if ((*it) == trk->getInstrument()) + break; + } + m_instrument->setCurrentItem(pos); + } else { + devId = m_playDeviceIds[m_playDevice->currentItem()]; + // set the new selected instrument for the track + int item = 0; + std::map<DeviceId, IdsVector>::const_iterator it; + for ( it = m_instrumentIds.begin(); it != m_instrumentIds.end(); ++it) { + if ( (*it).first == devId ) + break; + item += (*it).second.size(); + } + item += index; + RG_DEBUG << "TrackParameterBox::slotInstrumentChanged() item = " << item << "\n"; + emit instrumentSelected( m_selectedTrackId, item ); + } +} + +void +TrackParameterBox::slotRecordingDeviceChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::slotRecordingDeviceChanged(" << index << ")" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + Instrument *inst = m_doc->getStudio().getInstrumentById(trk->getInstrument()); + if (!inst) + return ; + if (inst->getInstrumentType() == Instrument::Audio) { + //Not implemented yet + } else { + trk->setMidiInputDevice(m_recDeviceIds[index]); + } +} + +void +TrackParameterBox::slotRecordingChannelChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::slotRecordingChannelChanged(" << index << ")" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + Instrument *inst = m_doc->getStudio().getInstrumentById(trk->getInstrument()); + if (!inst) + return ; + if (inst->getInstrumentType() == Instrument::Audio) { + //Not implemented yet + } else { + trk->setMidiInputChannel(index - 1); + } +} + +void +TrackParameterBox::slotInstrumentLabelChanged(InstrumentId id, QString label) +{ + RG_DEBUG << "TrackParameterBox::slotInstrumentLabelChanged(" << id << ") = " << label << "\n"; + populatePlaybackDeviceList(); + slotUpdateControls( -1); +} + +void +TrackParameterBox::showAdditionalControls(bool showThem) +{ + // m_defaultsGroup->parentWidget()->setShown(showThem); +} + +void +TrackParameterBox::slotClefChanged(int clef) +{ + RG_DEBUG << "TrackParameterBox::slotClefChanged(" << clef << ")" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + trk->setClef(clef); + m_presetLbl->setEnabled(false); +} + +void +TrackParameterBox::slotTransposeChanged(int transpose) +{ + RG_DEBUG << "TrackParameterBox::slotTransposeChanged(" << transpose << ")" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + trk->setTranspose(transpose); + m_presetLbl->setEnabled(false); +} + +void +TrackParameterBox::slotTransposeIndexChanged(int index) +{ + slotTransposeTextChanged(m_defTranspose->text(index)); +} + +void +TrackParameterBox::slotTransposeTextChanged(QString text) +{ + if (text.isEmpty()) + return ; + int value = text.toInt(); + slotTransposeChanged(value); +} + +void +TrackParameterBox::slotDocColoursChanged() +{ + RG_DEBUG << "TrackParameterBox::slotDocColoursChanged()" << endl; + + m_defColor->clear(); + m_colourList.clear(); + // Populate it from composition.m_segmentColourMap + ColourMap temp = m_doc->getComposition().getSegmentColourMap(); + + unsigned int i = 0; + + for (RCMap::const_iterator it = temp.begin(); it != temp.end(); ++it) { + QString qtrunc(strtoqstr(it->second.second)); + QPixmap colour(15, 15); + colour.fill(GUIPalette::convertColour(it->second.first)); + if (qtrunc == "") { + m_defColor->insertItem(colour, i18n("Default"), i); + } else { + // truncate name to 15 characters to avoid the combo forcing the + // whole kit and kaboodle too wide + if (qtrunc.length() > 15) + qtrunc = qtrunc.left(12) + "..."; + m_defColor->insertItem(colour, qtrunc, i); + } + m_colourList[it->first] = i; // maps colour number to menu index + ++i; + } + + m_addColourPos = i; + m_defColor->insertItem(i18n("Add New Color"), m_addColourPos); + + m_defColor->setCurrentItem(0); +} + +void +TrackParameterBox::slotColorChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::slotColorChanged(" << index << ")" << endl; + + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + + trk->setColor(index); + + if (index == m_addColourPos) { + ColourMap newMap = m_doc->getComposition().getSegmentColourMap(); + QColor newColour; + bool ok = false; + QString newName = KLineEditDlg::getText(i18n("New Color Name"), i18n("Enter new name"), + i18n("New"), &ok); + if ((ok == true) && (!newName.isEmpty())) { + KColorDialog box(this, "", true); + + int result = box.getColor(newColour); + + if (result == KColorDialog::Accepted) { + Colour newRColour = GUIPalette::convertColour(newColour); + newMap.addItem(newRColour, qstrtostr(newName)); + slotDocColoursChanged(); + } + } + // Else we don't do anything as they either didn't give a name� + // or didn't give a colour + } +} + +void +TrackParameterBox::slotHighestPressed() +{ + RG_DEBUG << "TrackParameterBox::slotHighestPressed()" << endl; + + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + + PitchPickerDialog dialog(0, m_highestPlayable, i18n("Highest playable note")); + + if (dialog.exec() == QDialog::Accepted) { + m_highestPlayable = dialog.getPitch(); + updateHighLow(); + } + + m_presetLbl->setEnabled(false); +} + +void +TrackParameterBox::slotLowestPressed() +{ + RG_DEBUG << "TrackParameterBox::slotLowestPressed()" << endl; + + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + + PitchPickerDialog dialog(0, m_lowestPlayable, i18n("Lowest playable note")); + + if (dialog.exec() == QDialog::Accepted) { + m_lowestPlayable = dialog.getPitch(); + updateHighLow(); + } + + m_presetLbl->setEnabled(false); +} + +void +TrackParameterBox::slotPresetPressed() +{ + RG_DEBUG << "TrackParameterBox::slotPresetPressed()" << endl; + + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(comp.getSelectedTrack()); + if (!trk) + return ; + + PresetHandlerDialog dialog(this); + + try { + if (dialog.exec() == QDialog::Accepted) { + m_presetLbl->setText(dialog.getName()); + trk->setPresetLabel(dialog.getName()); + if (dialog.getConvertAllSegments()) { + SegmentSyncCommand* command = new SegmentSyncCommand( + comp.getSegments(), comp.getSelectedTrack(), + dialog.getTranspose(), dialog.getLowRange(), + dialog.getHighRange(), + clefIndexToClef(dialog.getClef())); + m_doc->getCommandHistory()->addCommand(command); + } + m_defClef->setCurrentItem(dialog.getClef()); + m_defTranspose->setCurrentItem(QString("%1").arg + (dialog.getTranspose()), true); + + m_highestPlayable = dialog.getHighRange(); + m_lowestPlayable = dialog.getLowRange(); + updateHighLow(); + slotClefChanged(dialog.getClef()); + slotTransposeChanged(dialog.getTranspose()); + + // the preceding slots will have set this disabled, so we + // re-enable it until it is subsequently re-disabled by the + // user overriding the preset, calling one of the above slots + // in the normal course + m_presetLbl->setEnabled(true); + } + } catch (Exception e) { + //!!! This should be a more verbose error to pass along the + // row/column of the corruption, but I can't be bothered to work + // that out just at the moment. Hopefully this code will never + // execute anyway. + KMessageBox::sorry(0, i18n("The instrument preset database is corrupt. Check your installation.")); + } + +} + +void +TrackParameterBox::slotStaffSizeChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::sotStaffSizeChanged()" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + + trk->setStaffSize(index); +} + + +void +TrackParameterBox::slotStaffBracketChanged(int index) +{ + RG_DEBUG << "TrackParameterBox::sotStaffBracketChanged()" << endl; + Composition &comp = m_doc->getComposition(); + Track *trk = comp.getTrackById(m_selectedTrackId); + + trk->setStaffBracket(index); +} + +QString +TrackParameterBox::getPreviousBox(RosegardenParameterArea::Arrangement arrangement) const +{ + if (arrangement == RosegardenParameterArea::CLASSIC_STYLE) { + return i18n("Segment"); + } else { + return ""; + } +} + +} +#include "TrackParameterBox.moc" diff --git a/src/gui/editors/parameters/TrackParameterBox.h b/src/gui/editors/parameters/TrackParameterBox.h new file mode 100644 index 0000000..c5fa0f9 --- /dev/null +++ b/src/gui/editors/parameters/TrackParameterBox.h @@ -0,0 +1,161 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + This file is Copyright 2006 + Pedro Lopez-Cabanillas <[email protected]> + D. Michael McIntyre <[email protected]> + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_TRACKPARAMETERBOX_H_ +#define _RG_TRACKPARAMETERBOX_H_ + +#include "base/MidiProgram.h" +#include "base/Track.h" +#include "gui/widgets/ColourTable.h" +#include <map> +#include "RosegardenParameterArea.h" +#include "RosegardenParameterBox.h" +#include <qstring.h> +#include <qcheckbox.h> // #include <QCheckBox> in QT4, thinking ahead +#include <vector> + + +class QWidget; +class QPushButton; +class QLabel; +class QFrame; +class KComboBox; +class QCheckBox; + + +namespace Rosegarden +{ + +class RosegardenGUIDoc; + + +class TrackParameterBox : public RosegardenParameterBox +{ +Q_OBJECT + +public: + TrackParameterBox( RosegardenGUIDoc *doc, + QWidget *parent=0); + ~TrackParameterBox(); + + void setDocument( RosegardenGUIDoc *doc ); + void populateDeviceLists(); + virtual void showAdditionalControls(bool showThem); + + virtual QString getPreviousBox(RosegardenParameterArea::Arrangement) const; + +public slots: + void slotSelectedTrackChanged(); + void slotSelectedTrackNameChanged(); + void slotPlaybackDeviceChanged(int index); + void slotInstrumentChanged(int index); + void slotRecordingDeviceChanged(int index); + void slotRecordingChannelChanged(int index); + void slotUpdateControls(int); + void slotInstrumentLabelChanged(InstrumentId id, QString label); + + void slotClefChanged(int clef); + void slotTransposeChanged(int transpose); + void slotTransposeIndexChanged(int index); + void slotTransposeTextChanged(QString text); + void slotDocColoursChanged(); + void slotColorChanged(int index); + void slotHighestPressed(); + void slotLowestPressed(); + void slotPresetPressed(); + + void slotStaffSizeChanged(int index); + void slotStaffBracketChanged(int index); + +signals: + void instrumentSelected(TrackId, int); + +protected: + void populatePlaybackDeviceList(); + void populateRecordingDeviceList(); + void updateHighLow(); + +private: + RosegardenGUIDoc *m_doc; + + KComboBox *m_playDevice; + KComboBox *m_instrument; + KComboBox *m_recDevice; + KComboBox *m_recChannel; + + QPushButton *m_presetButton; + QPushButton *m_highButton; + QPushButton *m_lowButton; + + KComboBox *m_defClef; + KComboBox *m_defColor; + KComboBox *m_defTranspose; + KComboBox *m_staffSizeCombo; + KComboBox *m_staffBracketCombo; + + + int m_addColourPos; + int m_highestPlayable; + int m_lowestPlayable; + ColourTable::ColourList m_colourList; + + QLabel *m_trackLabel; + + typedef std::vector<DeviceId> IdsVector; + + IdsVector m_playDeviceIds; + IdsVector m_recDeviceIds; + + std::map<DeviceId, IdsVector> m_instrumentIds; + std::map<DeviceId, QStringList> m_instrumentNames; + + int m_selectedTrackId; + + char m_lastInstrumentType; + + // Additional elements that may be hidden in vertical stacked mode + //QFrame *m_separator2; + QFrame *m_playbackGroup; + QFrame *m_recordGroup; + QFrame *m_defaultsGroup; + QFrame *m_staffGroup; + QLabel *m_segHeader; + QLabel *m_presetLbl; + QLabel *m_staffGrpLbl; + QLabel *m_grandStaffLbl; + QLabel *m_clefLbl; + QLabel *m_transpLbl; + QLabel *m_colorLbl; + QLabel *m_rangeLbl; + QLabel *m_psetLbl; +}; + + +} + +#endif |