diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index f94c057e1..f0dd29ae8 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -1,6 +1,6 @@ /* - * InstrumentTrack.h - declaration of class InstrumentTrack, a track + window - * which holds an instrument-plugin + * InstrumentTrack.h - declaration of class InstrumentTrack, a track which + * holds an instrument-plugin * * Copyright (c) 2004-2014 Tobias Doerffel * @@ -27,45 +27,22 @@ #define INSTRUMENT_TRACK_H #include "AudioPort.h" -#include "GroupBox.h" #include "InstrumentFunctions.h" #include "InstrumentSoundShaping.h" #include "Microtuner.h" #include "Midi.h" -#include "MidiCCRackView.h" #include "MidiEventProcessor.h" #include "MidiPort.h" #include "NotePlayHandle.h" #include "Piano.h" -#include "PianoView.h" #include "Pitch.h" #include "Plugin.h" #include "Track.h" #include "TrackView.h" - -class QLineEdit; -class InstrumentFunctionArpeggioView; -class InstrumentFunctionNoteStackingView; -class EffectRackView; -class InstrumentSoundShapingView; -class FadeButton; class Instrument; -class InstrumentTrackWindow; -class InstrumentMidiIOView; -class InstrumentMiscView; -class Knob; -class FxLineLcdSpinBox; -class LcdSpinBox; -class LeftRightNav; -class midiPortMenu; class DataFile; -class PluginView; -class TabWidget; -class TrackLabelButton; -class LedCheckBox; -class QLabel; class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor @@ -327,196 +304,4 @@ private: } ; - - - -class InstrumentTrackView : public TrackView -{ - Q_OBJECT -public: - InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc ); - virtual ~InstrumentTrackView(); - - InstrumentTrackWindow * getInstrumentTrackWindow(); - - InstrumentTrack * model() - { - return castModel(); - } - - const InstrumentTrack * model() const - { - return castModel(); - } - - static InstrumentTrackWindow * topLevelInstrumentTrackWindow(); - - QMenu * midiMenu() - { - return m_midiMenu; - } - - // Create a menu for assigning/creating channels for this track - QMenu * createFxMenu( QString title, QString newFxLabel ) override; - - -protected: - void dragEnterEvent( QDragEnterEvent * _dee ) override; - void dropEvent( QDropEvent * _de ) override; - - -private slots: - void toggleInstrumentWindow( bool _on ); - void toggleMidiCCRack(); - void activityIndicatorPressed(); - void activityIndicatorReleased(); - - void midiInSelected(); - void midiOutSelected(); - void midiConfigChanged(); - - void assignFxLine( int channelIndex ); - void createFxLine(); - - void handleConfigChange(QString cls, QString attr, QString value); - - -private: - InstrumentTrackWindow * m_window; - - // widgets in track-settings-widget - TrackLabelButton * m_tlb; - Knob * m_volumeKnob; - Knob * m_panningKnob; - FadeButton * m_activityIndicator; - - QMenu * m_midiMenu; - - QAction * m_midiInputAction; - QAction * m_midiOutputAction; - - std::unique_ptr m_midiCCRackView; - - QPoint m_lastPos; - - FadeButton * getActivityIndicator() override - { - return m_activityIndicator; - } - - friend class InstrumentTrackWindow; - -} ; - - - - -class InstrumentTrackWindow : public QWidget, public ModelView, - public SerializingObjectHook -{ - Q_OBJECT -public: - InstrumentTrackWindow( InstrumentTrackView * _tv ); - virtual ~InstrumentTrackWindow(); - - // parent for all internal tab-widgets - TabWidget * tabWidgetParent() - { - return m_tabWidget; - } - - InstrumentTrack * model() - { - return castModel(); - } - - const InstrumentTrack * model() const - { - return castModel(); - } - - void setInstrumentTrackView( InstrumentTrackView * _tv ); - - InstrumentTrackView *instrumentTrackView() - { - return m_itv; - } - - - PianoView * pianoView() - { - return m_pianoView; - } - - static void dragEnterEventGeneric( QDragEnterEvent * _dee ); - - void dragEnterEvent( QDragEnterEvent * _dee ) override; - void dropEvent( QDropEvent * _de ) override; - - -public slots: - void textChanged( const QString & _new_name ); - void toggleVisibility( bool _on ); - void updateName(); - void updateInstrumentView(); - - -protected: - // capture close-events for toggling instrument-track-button - void closeEvent( QCloseEvent * _ce ) override; - void focusInEvent( QFocusEvent * _fe ) override; - - void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; - void loadSettings( const QDomElement & _this ) override; - - -protected slots: - void saveSettingsBtnClicked(); - void viewNextInstrument(); - void viewPrevInstrument(); - -private: - void modelChanged() override; - void viewInstrumentInDirection(int d); - //! adjust size of any child widget of the main tab - //! required to keep the old look when using a variable sized tab widget - void adjustTabSize(QWidget *w); - - InstrumentTrack * m_track; - InstrumentTrackView * m_itv; - - // widgets on the top of an instrument-track-window - QLineEdit * m_nameLineEdit; - LeftRightNav * m_leftRightNav; - Knob * m_volumeKnob; - Knob * m_panningKnob; - Knob * m_pitchKnob; - QLabel * m_pitchLabel; - LcdSpinBox* m_pitchRangeSpinBox; - QLabel * m_pitchRangeLabel; - FxLineLcdSpinBox * m_effectChannelNumber; - - - - // tab-widget with all children - TabWidget * m_tabWidget; - PluginView * m_instrumentView; - InstrumentSoundShapingView * m_ssView; - InstrumentFunctionNoteStackingView* m_noteStackingView; - InstrumentFunctionArpeggioView* m_arpeggioView; - InstrumentMidiIOView * m_midiView; - EffectRackView * m_effectView; - InstrumentMiscView *m_miscView; - - - // test-piano at the bottom of every instrument-settings-window - PianoView * m_pianoView; - - friend class InstrumentView; - friend class InstrumentTrackView; - -} ; - - - #endif diff --git a/include/InstrumentTrackView.h b/include/InstrumentTrackView.h new file mode 100644 index 000000000..03ae6839d --- /dev/null +++ b/include/InstrumentTrackView.h @@ -0,0 +1,118 @@ +/* + * InstrumentTrackView.h - declaration of InstrumentTrackView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * This file is part of LMMS - https://lmms.io + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef INSTRUMENT_TRACK_VIEW_H +#define INSTRUMENT_TRACK_VIEW_H + +#include "TrackView.h" + +#include "InstrumentTrack.h" +#include "MidiCCRackView.h" + + +class InstrumentTrackWindow; +class Knob; +class TrackContainerView; +class TrackLabelButton; + + +class InstrumentTrackView : public TrackView +{ + Q_OBJECT +public: + InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc ); + virtual ~InstrumentTrackView(); + + InstrumentTrackWindow * getInstrumentTrackWindow(); + + InstrumentTrack * model() + { + return castModel(); + } + + const InstrumentTrack * model() const + { + return castModel(); + } + + static InstrumentTrackWindow * topLevelInstrumentTrackWindow(); + + QMenu * midiMenu() + { + return m_midiMenu; + } + + // Create a menu for assigning/creating channels for this track + QMenu * createFxMenu( QString title, QString newFxLabel ) override; + + +protected: + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + + +private slots: + void toggleInstrumentWindow( bool _on ); + void toggleMidiCCRack(); + void activityIndicatorPressed(); + void activityIndicatorReleased(); + + void midiInSelected(); + void midiOutSelected(); + void midiConfigChanged(); + + void assignFxLine( int channelIndex ); + void createFxLine(); + + void handleConfigChange(QString cls, QString attr, QString value); + + +private: + InstrumentTrackWindow * m_window; + + // widgets in track-settings-widget + TrackLabelButton * m_tlb; + Knob * m_volumeKnob; + Knob * m_panningKnob; + FadeButton * m_activityIndicator; + + QMenu * m_midiMenu; + + QAction * m_midiInputAction; + QAction * m_midiOutputAction; + + std::unique_ptr m_midiCCRackView; + + QPoint m_lastPos; + + FadeButton * getActivityIndicator() override + { + return m_activityIndicator; + } + + friend class InstrumentTrackWindow; +} ; + +#endif + diff --git a/include/InstrumentTrackWindow.h b/include/InstrumentTrackWindow.h new file mode 100644 index 000000000..7a023a635 --- /dev/null +++ b/include/InstrumentTrackWindow.h @@ -0,0 +1,161 @@ +/* + * InstrumentTrackWindow.h - declaration of InstrumentTrackWindow class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * This file is part of LMMS - https://lmms.io + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef INSTRUMENT_TRACK_WINDOW_H +#define INSTRUMENT_TRACK_WINDOW_H + +#include + +#include "ModelView.h" +#include "SerializingObject.h" + + +class EffectRackView; +class FxLineLcdSpinBox; +class InstrumentFunctionArpeggioView; +class InstrumentFunctionNoteStackingView; +class InstrumentMidiIOView; +class InstrumentMiscView; +class InstrumentSoundShapingView; +class InstrumentTrack; +class InstrumentTrackShapingView; +class InstrumentTrackView; +class Knob; +class LcdSpinBox; +class LeftRightNav; +class PianoView; +class PluginView; +class QLabel; +class QLineEdit; +class QWidget; +class TabWidget; + + +class InstrumentTrackWindow : public QWidget, public ModelView, + public SerializingObjectHook +{ + Q_OBJECT +public: + InstrumentTrackWindow( InstrumentTrackView * _tv ); + virtual ~InstrumentTrackWindow(); + + // parent for all internal tab-widgets + TabWidget * tabWidgetParent() + { + return m_tabWidget; + } + + InstrumentTrack * model() + { + return castModel(); + } + + const InstrumentTrack * model() const + { + return castModel(); + } + + void setInstrumentTrackView( InstrumentTrackView * _tv ); + + InstrumentTrackView *instrumentTrackView() + { + return m_itv; + } + + + PianoView * pianoView() + { + return m_pianoView; + } + + static void dragEnterEventGeneric( QDragEnterEvent * _dee ); + + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + + +public slots: + void textChanged( const QString & _new_name ); + void toggleVisibility( bool _on ); + void updateName(); + void updateInstrumentView(); + + +protected: + // capture close-events for toggling instrument-track-button + void closeEvent( QCloseEvent * _ce ) override; + void focusInEvent( QFocusEvent * _fe ) override; + + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; + + +protected slots: + void saveSettingsBtnClicked(); + void viewNextInstrument(); + void viewPrevInstrument(); + +private: + void modelChanged() override; + void viewInstrumentInDirection(int d); + //! adjust size of any child widget of the main tab + //! required to keep the old look when using a variable sized tab widget + void adjustTabSize(QWidget *w); + + InstrumentTrack * m_track; + InstrumentTrackView * m_itv; + + // widgets on the top of an instrument-track-window + QLineEdit * m_nameLineEdit; + LeftRightNav * m_leftRightNav; + Knob * m_volumeKnob; + Knob * m_panningKnob; + Knob * m_pitchKnob; + QLabel * m_pitchLabel; + LcdSpinBox* m_pitchRangeSpinBox; + QLabel * m_pitchRangeLabel; + FxLineLcdSpinBox * m_effectChannelNumber; + + + + // tab-widget with all children + TabWidget * m_tabWidget; + PluginView * m_instrumentView; + InstrumentSoundShapingView * m_ssView; + InstrumentFunctionNoteStackingView* m_noteStackingView; + InstrumentFunctionArpeggioView* m_arpeggioView; + InstrumentMidiIOView * m_midiView; + EffectRackView * m_effectView; + InstrumentMiscView *m_miscView; + + + // test-piano at the bottom of every instrument-settings-window + PianoView * m_pianoView; + + friend class InstrumentView; + friend class InstrumentTrackView; +} ; + +#endif + diff --git a/plugins/Lv2Instrument/Lv2Instrument.cpp b/plugins/Lv2Instrument/Lv2Instrument.cpp index 30dfd80c5..b94e30aef 100644 --- a/plugins/Lv2Instrument/Lv2Instrument.cpp +++ b/plugins/Lv2Instrument/Lv2Instrument.cpp @@ -26,6 +26,7 @@ #include #include +#include #include "AudioEngine.h" #include "Engine.h" diff --git a/plugins/Lv2Instrument/Lv2Instrument.h b/plugins/Lv2Instrument/Lv2Instrument.h index 60575d426..00a0f35fb 100644 --- a/plugins/Lv2Instrument/Lv2Instrument.h +++ b/plugins/Lv2Instrument/Lv2Instrument.h @@ -37,8 +37,6 @@ // currently only MIDI works #define LV2_INSTRUMENT_USE_MIDI -class QPushButton; - class Lv2Instrument : public Instrument, public Lv2ControlBase { diff --git a/src/3rdparty/rpmalloc/rpmalloc b/src/3rdparty/rpmalloc/rpmalloc index 30cc0c7a8..80daac0d5 160000 --- a/src/3rdparty/rpmalloc/rpmalloc +++ b/src/3rdparty/rpmalloc/rpmalloc @@ -1 +1 @@ -Subproject commit 30cc0c7a8c1b4decdeb72d456b158f0995ca839e +Subproject commit 80daac0d539ab2a8edfd5ca24b1e0c77a4974bbb diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index a04f4bea4..695575b2e 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -19,6 +19,8 @@ SET(LMMS_SRCS gui/FxMixerView.cpp gui/GuiApplication.cpp gui/InstrumentView.cpp + gui/InstrumentTrackView.cpp + gui/InstrumentTrackWindow.cpp gui/LfoControllerDialog.cpp gui/LmmsPalette.cpp gui/LmmsStyle.cpp diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index 08bd04a22..fb61deada 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -48,6 +48,7 @@ #include "ImportFilter.h" #include "Instrument.h" #include "InstrumentTrack.h" +#include "InstrumentTrackWindow.h" #include "MainWindow.h" #include "PluginFactory.h" #include "PresetPreviewPlayHandle.h" diff --git a/src/gui/InstrumentTrackView.cpp b/src/gui/InstrumentTrackView.cpp new file mode 100644 index 000000000..17454a640 --- /dev/null +++ b/src/gui/InstrumentTrackView.cpp @@ -0,0 +1,386 @@ +/* + * InstrumentTrackView.cpp - implementation of InstrumentTrackView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * This file is part of LMMS - https://lmms.io + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "InstrumentTrackView.h" + +#include +#include +#include +#include +#include +#include + +#include "AudioEngine.h" +#include "ConfigManager.h" +#include "ControllerConnectionDialog.h" +#include "Engine.h" +#include "FadeButton.h" +#include "FxLineLcdSpinBox.h" +#include "FxMixer.h" +#include "FxMixerView.h" +#include "GuiApplication.h" +#include "InstrumentTrack.h" +#include "InstrumentTrackWindow.h" +#include "MainWindow.h" +#include "MidiClient.h" +#include "MidiPortMenu.h" +#include "TrackLabelButton.h" + + +InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tcv ) : + TrackView( _it, tcv ), + m_window( nullptr ), + m_lastPos( -1, -1 ) +{ + setAcceptDrops( true ); + setFixedHeight( 32 ); + + m_tlb = new TrackLabelButton( this, getTrackSettingsWidget() ); + m_tlb->setCheckable( true ); + m_tlb->setIcon( embed::getIconPixmap( "instrument_track" ) ); + m_tlb->move( 3, 1 ); + m_tlb->show(); + + connect( m_tlb, SIGNAL( toggled( bool ) ), + this, SLOT( toggleInstrumentWindow( bool ) ) ); + + connect( _it, SIGNAL( nameChanged() ), + m_tlb, SLOT( update() ) ); + + connect(ConfigManager::inst(), SIGNAL(valueChanged(QString, QString, QString)), + this, SLOT(handleConfigChange(QString, QString, QString))); + + // creation of widgets for track-settings-widget + int widgetWidth; + if( ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt() ) + { + widgetWidth = DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT; + } + else + { + widgetWidth = DEFAULT_SETTINGS_WIDGET_WIDTH; + } + + m_volumeKnob = new Knob( knobSmall_17, getTrackSettingsWidget(), + tr( "Volume" ) ); + m_volumeKnob->setVolumeKnob( true ); + m_volumeKnob->setModel( &_it->m_volumeModel ); + m_volumeKnob->setHintText( tr( "Volume:" ), "%" ); + m_volumeKnob->move( widgetWidth-2*24, 2 ); + m_volumeKnob->setLabel( tr( "VOL" ) ); + m_volumeKnob->show(); + + m_panningKnob = new Knob( knobSmall_17, getTrackSettingsWidget(), + tr( "Panning" ) ); + m_panningKnob->setModel( &_it->m_panningModel ); + m_panningKnob->setHintText(tr("Panning:"), "%"); + m_panningKnob->move( widgetWidth-24, 2 ); + m_panningKnob->setLabel( tr( "PAN" ) ); + m_panningKnob->show(); + + m_midiMenu = new QMenu( tr( "MIDI" ), this ); + + // sequenced MIDI? + if( !Engine::audioEngine()->midiClient()->isRaw() ) + { + _it->m_midiPort.m_readablePortsMenu = new MidiPortMenu( + MidiPort::Input ); + _it->m_midiPort.m_writablePortsMenu = new MidiPortMenu( + MidiPort::Output ); + _it->m_midiPort.m_readablePortsMenu->setModel( + &_it->m_midiPort ); + _it->m_midiPort.m_writablePortsMenu->setModel( + &_it->m_midiPort ); + m_midiInputAction = m_midiMenu->addMenu( + _it->m_midiPort.m_readablePortsMenu ); + m_midiOutputAction = m_midiMenu->addMenu( + _it->m_midiPort.m_writablePortsMenu ); + } + else + { + m_midiInputAction = m_midiMenu->addAction( "" ); + m_midiOutputAction = m_midiMenu->addAction( "" ); + m_midiInputAction->setCheckable( true ); + m_midiOutputAction->setCheckable( true ); + connect( m_midiInputAction, SIGNAL( changed() ), this, + SLOT( midiInSelected() ) ); + connect( m_midiOutputAction, SIGNAL( changed() ), this, + SLOT( midiOutSelected() ) ); + connect( &_it->m_midiPort, SIGNAL( modeChanged() ), + this, SLOT( midiConfigChanged() ) ); + } + + m_midiInputAction->setText( tr( "Input" ) ); + m_midiOutputAction->setText( tr( "Output" ) ); + + QAction *midiRackAction = m_midiMenu->addAction(tr("Open/Close MIDI CC Rack")); + midiRackAction->setIcon(embed::getIconPixmap("midi_cc_rack")); + connect(midiRackAction, SIGNAL(triggered()), + this, SLOT(toggleMidiCCRack())); + + m_activityIndicator = new FadeButton( QApplication::palette().color( QPalette::Active, + QPalette::Background), + QApplication::palette().color( QPalette::Active, + QPalette::BrightText ), + QApplication::palette().color( QPalette::Active, + QPalette::BrightText).darker(), + getTrackSettingsWidget() ); + m_activityIndicator->setGeometry( + widgetWidth-2*24-11, 2, 8, 28 ); + m_activityIndicator->show(); + connect( m_activityIndicator, SIGNAL( pressed() ), + this, SLOT( activityIndicatorPressed() ) ); + connect( m_activityIndicator, SIGNAL( released() ), + this, SLOT( activityIndicatorReleased() ) ); + connect( _it, SIGNAL( newNote() ), + m_activityIndicator, SLOT( activate() ) ); + connect( _it, SIGNAL( endNote() ), + m_activityIndicator, SLOT( noteEnd() ) ); + + setModel( _it ); +} + + + + +InstrumentTrackView::~InstrumentTrackView() +{ + delete m_window; + m_window = nullptr; + + delete model()->m_midiPort.m_readablePortsMenu; + delete model()->m_midiPort.m_writablePortsMenu; +} + + + + +void InstrumentTrackView::toggleMidiCCRack() +{ + // Lazy creation: midiCCRackView is only created when accessed the first time. + // this->model() returns pointer to the InstrumentTrack who owns this InstrumentTrackView. + if (!m_midiCCRackView) + { + m_midiCCRackView = std::unique_ptr(new MidiCCRackView(this->model())); + } + + if (m_midiCCRackView->parentWidget()->isVisible()) + { + m_midiCCRackView->parentWidget()->hide(); + } + else + { + m_midiCCRackView->parentWidget()->show(); + m_midiCCRackView->show(); + } +} + + + + +InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() +{ + InstrumentTrackWindow * w = nullptr; + for( const QMdiSubWindow * sw : + getGUI()->mainWindow()->workspace()->subWindowList( + QMdiArea::ActivationHistoryOrder ) ) + { + if( sw->isVisible() && sw->widget()->inherits( "InstrumentTrackWindow" ) ) + { + w = qobject_cast( sw->widget() ); + } + } + + return w; +} + + + + +/*! \brief Create and assign a new FX Channel for this track */ +void InstrumentTrackView::createFxLine() +{ + int channelIndex = getGUI()->fxMixerView()->addNewChannel(); + auto channel = Engine::fxMixer()->effectChannel(channelIndex); + + channel->m_name = getTrack()->name(); + if (getTrack()->useColor()) { channel->setColor (getTrack()->color()); } + + assignFxLine(channelIndex); +} + + + + +/*! \brief Assign a specific FX Channel for this track */ +void InstrumentTrackView::assignFxLine(int channelIndex) +{ + model()->effectChannelModel()->setValue( channelIndex ); + + getGUI()->fxMixerView()->setCurrentFxLine( channelIndex ); +} + + + +InstrumentTrackWindow * InstrumentTrackView::getInstrumentTrackWindow() +{ + if (!m_window) + { + m_window = new InstrumentTrackWindow(this); + } + + return m_window; +} + +void InstrumentTrackView::handleConfigChange(QString cls, QString attr, QString value) +{ + // When one instrument track window mode is turned on, + // close windows except last opened one. + if (cls == "ui" && attr == "oneinstrumenttrackwindow" && value.toInt()) + { + m_tlb->setChecked(m_window && m_window == topLevelInstrumentTrackWindow()); + } +} + +void InstrumentTrackView::dragEnterEvent( QDragEnterEvent * _dee ) +{ + InstrumentTrackWindow::dragEnterEventGeneric( _dee ); + if( !_dee->isAccepted() ) + { + TrackView::dragEnterEvent( _dee ); + } +} + + + + +void InstrumentTrackView::dropEvent( QDropEvent * _de ) +{ + getInstrumentTrackWindow()->dropEvent( _de ); + TrackView::dropEvent( _de ); +} + + + + +void InstrumentTrackView::toggleInstrumentWindow( bool _on ) +{ + if (_on && ConfigManager::inst()->value("ui", "oneinstrumenttrackwindow").toInt()) + { + if (topLevelInstrumentTrackWindow()) + { + topLevelInstrumentTrackWindow()->m_itv->m_tlb->setChecked(false); + } + } + + getInstrumentTrackWindow()->toggleVisibility( _on ); +} + + + + +void InstrumentTrackView::activityIndicatorPressed() +{ + model()->processInEvent( MidiEvent( MidiNoteOn, 0, DefaultKey, MidiDefaultVelocity ) ); +} + + + + +void InstrumentTrackView::activityIndicatorReleased() +{ + model()->processInEvent( MidiEvent( MidiNoteOff, 0, DefaultKey, 0 ) ); +} + + + + + +void InstrumentTrackView::midiInSelected() +{ + if( model() ) + { + model()->m_midiPort.setReadable( m_midiInputAction->isChecked() ); + } +} + + + + +void InstrumentTrackView::midiOutSelected() +{ + if( model() ) + { + model()->m_midiPort.setWritable( m_midiOutputAction->isChecked() ); + } +} + + + + +void InstrumentTrackView::midiConfigChanged() +{ + m_midiInputAction->setChecked( model()->m_midiPort.isReadable() ); + m_midiOutputAction->setChecked( model()->m_midiPort.isWritable() ); +} + + + + +//FIXME: This is identical to SampleTrackView::createFxMenu +QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) +{ + int channelIndex = model()->effectChannelModel()->value(); + + FxChannel *fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); + + // If title allows interpolation, pass channel index and name + if ( title.contains( "%2" ) ) + { + title = title.arg( channelIndex ).arg( fxChannel->m_name ); + } + + QMenu *fxMenu = new QMenu( title ); + + fxMenu->addAction( newFxLabel, this, SLOT( createFxLine() ) ); + fxMenu->addSeparator(); + + for (int i = 0; i < Engine::fxMixer()->numChannels(); ++i) + { + FxChannel * currentChannel = Engine::fxMixer()->effectChannel( i ); + + if ( currentChannel != fxChannel ) + { + auto index = currentChannel->m_channelIndex; + QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); + fxMenu->addAction(label, [this, index](){ + assignFxLine(index); + }); + } + } + + return fxMenu; +} + diff --git a/src/gui/InstrumentTrackWindow.cpp b/src/gui/InstrumentTrackWindow.cpp new file mode 100644 index 000000000..cda4e44f8 --- /dev/null +++ b/src/gui/InstrumentTrackWindow.cpp @@ -0,0 +1,673 @@ +/* + * InstrumentTrackWindow.cpp - implementation of InstrumentTrackWindow class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * This file is part of LMMS - https://lmms.io + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "InstrumentTrackWindow.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "ComboBox.h" +#include "ConfigManager.h" +#include "DataFile.h" +#include "EffectRackView.h" +#include "embed.h" +#include "Engine.h" +#include "FileBrowser.h" +#include "FileDialog.h" +#include "FxLineLcdSpinBox.h" +#include "FxMixer.h" +#include "GuiApplication.h" +#include "gui_templates.h" +#include "Instrument.h" +#include "InstrumentFunctions.h" +#include "InstrumentFunctionViews.h" +#include "InstrumentMidiIOView.h" +#include "InstrumentMiscView.h" +#include "InstrumentSoundShapingView.h" +#include "InstrumentTrack.h" +#include "InstrumentTrackView.h" +#include "LcdSpinBox.h" +#include "LedCheckbox.h" +#include "LeftRightNav.h" +#include "MainWindow.h" +#include "PianoView.h" +#include "PluginFactory.h" +#include "PluginView.h" +#include "Song.h" +#include "StringPairDrag.h" +#include "TabWidget.h" +#include "ToolTip.h" +#include "TrackContainerView.h" +#include "TrackLabelButton.h" + + +const int INSTRUMENT_WIDTH = 254; +const int INSTRUMENT_HEIGHT = INSTRUMENT_WIDTH; +const int PIANO_HEIGHT = 80; + + +InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) : + QWidget(), + ModelView( nullptr, this ), + m_track( _itv->model() ), + m_itv( _itv ), + m_instrumentView( nullptr ) +{ + setAcceptDrops( true ); + + // init own layout + widgets + setFocusPolicy( Qt::StrongFocus ); + QVBoxLayout * vlayout = new QVBoxLayout( this ); + vlayout->setMargin( 0 ); + vlayout->setSpacing( 0 ); + + TabWidget* generalSettingsWidget = new TabWidget( tr( "GENERAL SETTINGS" ), this ); + + QVBoxLayout* generalSettingsLayout = new QVBoxLayout( generalSettingsWidget ); + + generalSettingsLayout->setContentsMargins( 8, 18, 8, 8 ); + generalSettingsLayout->setSpacing( 6 ); + + QWidget* nameAndChangeTrackWidget = new QWidget( generalSettingsWidget ); + QHBoxLayout* nameAndChangeTrackLayout = new QHBoxLayout( nameAndChangeTrackWidget ); + nameAndChangeTrackLayout->setContentsMargins( 0, 0, 0, 0 ); + nameAndChangeTrackLayout->setSpacing( 2 ); + + // setup line edit for changing instrument track name + m_nameLineEdit = new QLineEdit; + m_nameLineEdit->setFont( pointSize<9>( m_nameLineEdit->font() ) ); + connect( m_nameLineEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged( const QString & ) ) ); + + m_nameLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); + nameAndChangeTrackLayout->addWidget(m_nameLineEdit, 1); + + + // set up left/right arrows for changing instrument + m_leftRightNav = new LeftRightNav(this); + connect( m_leftRightNav, SIGNAL( onNavLeft() ), this, + SLOT( viewPrevInstrument() ) ); + connect( m_leftRightNav, SIGNAL( onNavRight() ), this, + SLOT( viewNextInstrument() ) ); + // m_leftRightNav->setShortcuts(); + nameAndChangeTrackLayout->addWidget(m_leftRightNav); + + + generalSettingsLayout->addWidget( nameAndChangeTrackWidget ); + + + + QGridLayout* basicControlsLayout = new QGridLayout; + basicControlsLayout->setHorizontalSpacing(3); + basicControlsLayout->setVerticalSpacing(0); + basicControlsLayout->setContentsMargins(0, 0, 0, 0); + + QString labelStyleSheet = "font-size: 6pt;"; + Qt::Alignment labelAlignment = Qt::AlignHCenter | Qt::AlignTop; + Qt::Alignment widgetAlignment = Qt::AlignHCenter | Qt::AlignCenter; + + // set up volume knob + m_volumeKnob = new Knob( knobBright_26, nullptr, tr( "Volume" ) ); + m_volumeKnob->setVolumeKnob( true ); + m_volumeKnob->setHintText( tr( "Volume:" ), "%" ); + + basicControlsLayout->addWidget( m_volumeKnob, 0, 0 ); + basicControlsLayout->setAlignment( m_volumeKnob, widgetAlignment ); + + QLabel *label = new QLabel( tr( "VOL" ), this ); + label->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( label, 1, 0); + basicControlsLayout->setAlignment( label, labelAlignment ); + + + // set up panning knob + m_panningKnob = new Knob( knobBright_26, nullptr, tr( "Panning" ) ); + m_panningKnob->setHintText( tr( "Panning:" ), "" ); + + basicControlsLayout->addWidget( m_panningKnob, 0, 1 ); + basicControlsLayout->setAlignment( m_panningKnob, widgetAlignment ); + + label = new QLabel( tr( "PAN" ), this ); + label->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( label, 1, 1); + basicControlsLayout->setAlignment( label, labelAlignment ); + + + basicControlsLayout->setColumnStretch(2, 1); + + + // set up pitch knob + m_pitchKnob = new Knob( knobBright_26, nullptr, tr( "Pitch" ) ); + m_pitchKnob->setHintText( tr( "Pitch:" ), " " + tr( "cents" ) ); + + basicControlsLayout->addWidget( m_pitchKnob, 0, 3 ); + basicControlsLayout->setAlignment( m_pitchKnob, widgetAlignment ); + + m_pitchLabel = new QLabel( tr( "PITCH" ), this ); + m_pitchLabel->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( m_pitchLabel, 1, 3); + basicControlsLayout->setAlignment( m_pitchLabel, labelAlignment ); + + + // set up pitch range knob + m_pitchRangeSpinBox= new LcdSpinBox( 2, nullptr, tr( "Pitch range (semitones)" ) ); + + basicControlsLayout->addWidget( m_pitchRangeSpinBox, 0, 4 ); + basicControlsLayout->setAlignment( m_pitchRangeSpinBox, widgetAlignment ); + + m_pitchRangeLabel = new QLabel( tr( "RANGE" ), this ); + m_pitchRangeLabel->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( m_pitchRangeLabel, 1, 4); + basicControlsLayout->setAlignment( m_pitchRangeLabel, labelAlignment ); + + + basicControlsLayout->setColumnStretch(5, 1); + + + // setup spinbox for selecting FX-channel + m_effectChannelNumber = new FxLineLcdSpinBox( 2, nullptr, tr( "FX channel" ), m_itv ); + + basicControlsLayout->addWidget( m_effectChannelNumber, 0, 6 ); + basicControlsLayout->setAlignment( m_effectChannelNumber, widgetAlignment ); + + label = new QLabel( tr( "FX" ), this ); + label->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( label, 1, 6); + basicControlsLayout->setAlignment( label, labelAlignment ); + + QPushButton* saveSettingsBtn = new QPushButton( embed::getIconPixmap( "project_save" ), QString() ); + saveSettingsBtn->setMinimumSize( 32, 32 ); + + connect( saveSettingsBtn, SIGNAL( clicked() ), this, SLOT( saveSettingsBtnClicked() ) ); + + ToolTip::add( saveSettingsBtn, tr( "Save current instrument track settings in a preset file" ) ); + + basicControlsLayout->addWidget( saveSettingsBtn, 0, 7 ); + + label = new QLabel( tr( "SAVE" ), this ); + label->setStyleSheet( labelStyleSheet ); + basicControlsLayout->addWidget( label, 1, 7); + basicControlsLayout->setAlignment( label, labelAlignment ); + + generalSettingsLayout->addLayout( basicControlsLayout ); + + + m_tabWidget = new TabWidget( "", this, true, true ); + // "-1" : + // in "TabWidget::addTab", under "Position tab's window", the widget is + // moved up by 1 pixel + m_tabWidget->setMinimumHeight( INSTRUMENT_HEIGHT + GRAPHIC_TAB_HEIGHT - 4 - 1 ); + + + // create tab-widgets + m_ssView = new InstrumentSoundShapingView( m_tabWidget ); + + // FUNC tab + QWidget* instrumentFunctions = new QWidget( m_tabWidget ); + QVBoxLayout* instrumentFunctionsLayout = new QVBoxLayout( instrumentFunctions ); + instrumentFunctionsLayout->setMargin( 5 ); + m_noteStackingView = new InstrumentFunctionNoteStackingView( &m_track->m_noteStacking ); + m_arpeggioView = new InstrumentFunctionArpeggioView( &m_track->m_arpeggio ); + + instrumentFunctionsLayout->addWidget( m_noteStackingView ); + instrumentFunctionsLayout->addWidget( m_arpeggioView ); + instrumentFunctionsLayout->addStretch(); + + // MIDI tab + m_midiView = new InstrumentMidiIOView( m_tabWidget ); + + // FX tab + m_effectView = new EffectRackView( m_track->m_audioPort.effects(), m_tabWidget ); + + // MISC tab + m_miscView = new InstrumentMiscView( m_track, m_tabWidget ); + + + m_tabWidget->addTab( m_ssView, tr( "Envelope, filter & LFO" ), "env_lfo_tab", 1 ); + m_tabWidget->addTab( instrumentFunctions, tr( "Chord stacking & arpeggio" ), "func_tab", 2 ); + m_tabWidget->addTab( m_effectView, tr( "Effects" ), "fx_tab", 3 ); + m_tabWidget->addTab( m_midiView, tr( "MIDI" ), "midi_tab", 4 ); + m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 ); + adjustTabSize(m_ssView); + adjustTabSize(instrumentFunctions); + m_effectView->resize(EffectRackView::DEFAULT_WIDTH, INSTRUMENT_HEIGHT - 4 - 1); + adjustTabSize(m_midiView); + adjustTabSize(m_miscView); + + // setup piano-widget + m_pianoView = new PianoView( this ); + m_pianoView->setMinimumHeight( PIANO_HEIGHT ); + m_pianoView->setMaximumHeight( PIANO_HEIGHT ); + + vlayout->addWidget( generalSettingsWidget ); + // Use QWidgetItem explicitly to make the size hint change on instrument changes + // QLayout::addWidget() uses QWidgetItemV2 with size hint caching + vlayout->insertItem(1, new QWidgetItem(m_tabWidget)); + vlayout->addWidget( m_pianoView ); + setModel( _itv->model() ); + + QMdiSubWindow* subWin = getGUI()->mainWindow()->addWindowedWidget( this ); + Qt::WindowFlags flags = subWin->windowFlags(); + flags |= Qt::MSWindowsFixedSizeDialogHint; + flags &= ~Qt::WindowMaximizeButtonHint; + subWin->setWindowFlags( flags ); + + updateInstrumentView(); + + // Hide the Size and Maximize options from the system menu + // since the dialog size is fixed. + QMenu * systemMenu = subWin->systemMenu(); + systemMenu->actions().at( 2 )->setVisible( false ); // Size + systemMenu->actions().at( 4 )->setVisible( false ); // Maximize + + subWin->setWindowIcon( embed::getIconPixmap( "instrument_track" ) ); + subWin->setMinimumSize( subWin->size() ); + subWin->hide(); +} + + + + +InstrumentTrackWindow::~InstrumentTrackWindow() +{ + delete m_instrumentView; + + if (parentWidget()) + { + parentWidget()->hide(); + parentWidget()->deleteLater(); + } +} + + + + +void InstrumentTrackWindow::setInstrumentTrackView( InstrumentTrackView* view ) +{ + if( m_itv && view ) + { + m_itv->m_tlb->setChecked( false ); + } + + m_itv = view; + m_effectChannelNumber->setTrackView(m_itv); +} + + + + +void InstrumentTrackWindow::modelChanged() +{ + m_track = castModel(); + + m_nameLineEdit->setText( m_track->name() ); + + m_track->disconnect( SIGNAL( nameChanged() ), this ); + m_track->disconnect( SIGNAL( instrumentChanged() ), this ); + + connect( m_track, SIGNAL( nameChanged() ), + this, SLOT( updateName() ) ); + connect( m_track, SIGNAL( instrumentChanged() ), + this, SLOT( updateInstrumentView() ) ); + + m_volumeKnob->setModel( &m_track->m_volumeModel ); + m_panningKnob->setModel( &m_track->m_panningModel ); + m_effectChannelNumber->setModel( &m_track->m_effectChannelModel ); + m_pianoView->setModel( &m_track->m_piano ); + + if( m_track->instrument() && m_track->instrument()->flags().testFlag( Instrument::IsNotBendable ) == false ) + { + m_pitchKnob->setModel( &m_track->m_pitchModel ); + m_pitchRangeSpinBox->setModel( &m_track->m_pitchRangeModel ); + m_pitchKnob->show(); + m_pitchLabel->show(); + m_pitchRangeSpinBox->show(); + m_pitchRangeLabel->show(); + } + else + { + m_pitchKnob->hide(); + m_pitchLabel->hide(); + m_pitchKnob->setModel( nullptr ); + m_pitchRangeSpinBox->hide(); + m_pitchRangeLabel->hide(); + } + + if (m_track->instrument() && m_track->instrument()->flags().testFlag(Instrument::IsMidiBased)) + { + m_miscView->microtunerGroupBox()->hide(); + m_track->m_microtuner.enabledModel()->setValue(false); + } + else + { + m_miscView->microtunerGroupBox()->show(); + } + + m_ssView->setModel( &m_track->m_soundShaping ); + m_noteStackingView->setModel( &m_track->m_noteStacking ); + m_arpeggioView->setModel( &m_track->m_arpeggio ); + m_midiView->setModel( &m_track->m_midiPort ); + m_effectView->setModel( m_track->m_audioPort.effects() ); + m_miscView->pitchGroupBox()->setModel(&m_track->m_useMasterPitchModel); + m_miscView->microtunerGroupBox()->setModel(m_track->m_microtuner.enabledModel()); + m_miscView->scaleCombo()->setModel(m_track->m_microtuner.scaleModel()); + m_miscView->keymapCombo()->setModel(m_track->m_microtuner.keymapModel()); + m_miscView->rangeImportCheckbox()->setModel(m_track->m_microtuner.keyRangeImportModel()); + updateName(); +} + + + + +void InstrumentTrackWindow::saveSettingsBtnClicked() +{ + FileDialog sfd( this, tr( "Save preset" ), "", tr( "XML preset file (*.xpf)" ) ); + + QString presetRoot = ConfigManager::inst()->userPresetsDir(); + if( !QDir( presetRoot ).exists() ) + { + QDir().mkdir( presetRoot ); + } + if( !QDir( presetRoot + m_track->instrumentName() ).exists() ) + { + QDir( presetRoot ).mkdir( m_track->instrumentName() ); + } + + sfd.setAcceptMode( FileDialog::AcceptSave ); + sfd.setDirectory( presetRoot + m_track->instrumentName() ); + sfd.setFileMode( FileDialog::AnyFile ); + QString fname = m_track->name(); + sfd.selectFile(fname.remove(QRegExp(FILENAME_FILTER))); + sfd.setDefaultSuffix( "xpf"); + + if( sfd.exec() == QDialog::Accepted && + !sfd.selectedFiles().isEmpty() && + !sfd.selectedFiles().first().isEmpty() ) + { + DataFile dataFile( DataFile::InstrumentTrackSettings ); + m_track->setSimpleSerializing(); + m_track->saveSettings( dataFile, dataFile.content() ); + QString f = sfd.selectedFiles()[0]; + dataFile.writeFile( f ); + } +} + + + + + +void InstrumentTrackWindow::updateName() +{ + setWindowTitle( m_track->name().length() > 25 ? ( m_track->name().left(24)+"..." ) : m_track->name() ); + + if( m_nameLineEdit->text() != m_track->name() ) + { + m_nameLineEdit->setText( m_track->name() ); + } +} + + + + + +void InstrumentTrackWindow::updateInstrumentView() +{ + delete m_instrumentView; + if( m_track->m_instrument != nullptr ) + { + m_instrumentView = m_track->m_instrument->createView( m_tabWidget ); + m_tabWidget->addTab( m_instrumentView, tr( "Plugin" ), "plugin_tab", 0 ); + m_tabWidget->setActiveTab( 0 ); + + m_ssView->setFunctionsHidden( m_track->m_instrument->flags().testFlag( Instrument::IsSingleStreamed ) ); + + modelChanged(); // Get the instrument window to refresh + m_track->dataChanged(); // Get the text on the trackButton to change + + adjustTabSize(m_instrumentView); + m_pianoView->setVisible(m_track->m_instrument->hasNoteInput()); + // adjust window size + layout()->invalidate(); + resize(sizeHint()); + if (parentWidget()) + { + parentWidget()->resize(parentWidget()->sizeHint()); + } + update(); + m_instrumentView->update(); + } +} + + + + +void InstrumentTrackWindow::textChanged( const QString& newName ) +{ + m_track->setName( newName ); + Engine::getSong()->setModified(); +} + + + + +void InstrumentTrackWindow::toggleVisibility( bool on ) +{ + if( on ) + { + show(); + parentWidget()->show(); + parentWidget()->raise(); + } + else + { + parentWidget()->hide(); + } +} + + + + +void InstrumentTrackWindow::closeEvent( QCloseEvent* event ) +{ + event->ignore(); + + if( getGUI()->mainWindow()->workspace() ) + { + parentWidget()->hide(); + } + else + { + hide(); + } + + m_itv->m_tlb->setFocus(); + m_itv->m_tlb->setChecked( false ); +} + + + + +void InstrumentTrackWindow::focusInEvent( QFocusEvent* ) +{ + if(m_pianoView->isVisible()) { + m_pianoView->setFocus(); + } +} + + + + +void InstrumentTrackWindow::dragEnterEventGeneric( QDragEnterEvent* event ) +{ + StringPairDrag::processDragEnterEvent( event, "instrument,presetfile,pluginpresetfile" ); +} + + + + +void InstrumentTrackWindow::dragEnterEvent( QDragEnterEvent* event ) +{ + dragEnterEventGeneric( event ); +} + + + + +void InstrumentTrackWindow::dropEvent( QDropEvent* event ) +{ + QString type = StringPairDrag::decodeKey( event ); + QString value = StringPairDrag::decodeValue( event ); + + if( type == "instrument" ) + { + m_track->loadInstrument( value, nullptr, true /* DnD */ ); + + Engine::getSong()->setModified(); + + event->accept(); + setFocus(); + } + else if( type == "presetfile" ) + { + DataFile dataFile(value); + m_track->replaceInstrument(dataFile); + event->accept(); + setFocus(); + } + else if( type == "pluginpresetfile" ) + { + const QString ext = FileItem::extension( value ); + Instrument * i = m_track->instrument(); + + if( !i->descriptor()->supportsFileType( ext ) ) + { + PluginFactory::PluginInfoAndKey piakn = + getPluginFactory()->pluginSupportingExtension(ext); + i = m_track->loadInstrument(piakn.info.name(), &piakn.key); + } + + i->loadFile( value ); + + event->accept(); + setFocus(); + } +} + + + + +void InstrumentTrackWindow::saveSettings( QDomDocument& doc, QDomElement & thisElement ) +{ + thisElement.setAttribute( "tab", m_tabWidget->activeTab() ); + MainWindow::saveWidgetState( this, thisElement ); +} + + + + +void InstrumentTrackWindow::loadSettings( const QDomElement& thisElement ) +{ + m_tabWidget->setActiveTab( thisElement.attribute( "tab" ).toInt() ); + MainWindow::restoreWidgetState( this, thisElement ); + if( isVisible() ) + { + m_itv->m_tlb->setChecked( true ); + } +} + +void InstrumentTrackWindow::viewInstrumentInDirection(int d) +{ + // helper routine for viewNextInstrument, viewPrevInstrument + // d=-1 to view the previous instrument, + // d=+1 to view the next instrument + + const QList &trackViews = m_itv->trackContainerView()->trackViews(); + int idxOfMe = trackViews.indexOf(m_itv); + + // search for the next InstrumentTrackView (i.e. skip AutomationViews, etc) + // sometimes, the next InstrumentTrackView may already be open, in which case + // replace our window contents with the *next* closed Instrument Track and + // give focus to the InstrumentTrackView we skipped. + int idxOfNext = idxOfMe; + InstrumentTrackView *newView = nullptr; + InstrumentTrackView *bringToFront = nullptr; + do + { + idxOfNext = (idxOfNext + d + trackViews.size()) % trackViews.size(); + newView = dynamic_cast(trackViews[idxOfNext]); + // the window that should be brought to focus is the FIRST InstrumentTrackView that comes after us + if (bringToFront == nullptr && newView != nullptr) + { + bringToFront = newView; + } + // if the next instrument doesn't have an active window, then exit loop & load that one into our window. + if (newView != nullptr && !newView->m_tlb->isChecked()) + { + break; + } + } while (idxOfNext != idxOfMe); + + // avoid reloading the window if there is only one instrument, as that will just change the active tab + if (idxOfNext != idxOfMe) + { + // save current window pos and then hide the window by unchecking its button in the track list + QPoint curPos = parentWidget()->pos(); + m_itv->m_tlb->setChecked(false); + + // enable the new window by checking its track list button & moving it to where our window just was + newView->m_tlb->setChecked(true); + newView->getInstrumentTrackWindow()->parentWidget()->move(curPos); + + // scroll the SongEditor/BB-editor to make sure the new trackview label is visible + bringToFront->trackContainerView()->scrollToTrackView(bringToFront); + + // get the instrument window to refresh + modelChanged(); + } + Q_ASSERT(bringToFront); + bringToFront->getInstrumentTrackWindow()->setFocus(); +} + +void InstrumentTrackWindow::viewNextInstrument() +{ + viewInstrumentInDirection(+1); +} +void InstrumentTrackWindow::viewPrevInstrument() +{ + viewInstrumentInDirection(-1); +} + +void InstrumentTrackWindow::adjustTabSize(QWidget *w) +{ + // "-1" : + // in "TabWidget::addTab", under "Position tab's window", the widget is + // moved up by 1 pixel + w->setMinimumSize(INSTRUMENT_WIDTH - 4, INSTRUMENT_HEIGHT - 4 - 1); +} + diff --git a/src/gui/InstrumentView.cpp b/src/gui/InstrumentView.cpp index 42839f7d0..80594a04a 100644 --- a/src/gui/InstrumentView.cpp +++ b/src/gui/InstrumentView.cpp @@ -27,6 +27,7 @@ #include "InstrumentView.h" #include "embed.h" #include "InstrumentTrack.h" +#include "InstrumentTrackWindow.h" #include "StringPairDrag.h" diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 72f9522af..461802686 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -51,9 +51,11 @@ #include "FxMixerView.h" #include "GuiApplication.h" #include "ImportFilter.h" -#include "InstrumentTrack.h" +#include "InstrumentTrackView.h" +#include "InstrumentTrackWindow.h" #include "MicrotunerConfig.h" #include "PianoRoll.h" +#include "PianoView.h" #include "PluginBrowser.h" #include "PluginFactory.h" #include "PluginView.h" diff --git a/src/gui/TrackContentObjectView.cpp b/src/gui/TrackContentObjectView.cpp index 48b5a0127..6fcb500ef 100644 --- a/src/gui/TrackContentObjectView.cpp +++ b/src/gui/TrackContentObjectView.cpp @@ -39,6 +39,7 @@ #include "embed.h" #include "GuiApplication.h" #include "InstrumentTrack.h" +#include "InstrumentTrackView.h" #include "Note.h" #include "Pattern.h" #include "SampleTrack.h" diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index b0a93149e..4c9543265 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -64,6 +64,7 @@ #include "InstrumentTrack.h" #include "MainWindow.h" #include "Pattern.h" +#include "PianoView.h" #include "SongEditor.h" #include "StepRecorderWidget.h" #include "TextFloat.h" diff --git a/src/gui/widgets/TrackOperationsWidget.cpp b/src/gui/widgets/TrackOperationsWidget.cpp index d987dcac2..2f1a1aeed 100644 --- a/src/gui/widgets/TrackOperationsWidget.cpp +++ b/src/gui/widgets/TrackOperationsWidget.cpp @@ -39,7 +39,7 @@ #include "embed.h" #include "Engine.h" #include "gui_templates.h" -#include "InstrumentTrack.h" +#include "InstrumentTrackView.h" #include "PixmapButton.h" #include "Song.h" #include "StringPairDrag.h" diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 1e7bcb794..d7904b38e 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -1,6 +1,5 @@ /* - * InstrumentTrack.cpp - implementation of instrument-track-class - * (window + data-structures) + * InstrumentTrack.cpp - implementation of InstrumentTrack class * * Copyright (c) 2004-2014 Tobias Doerffel * @@ -24,68 +23,21 @@ */ #include "InstrumentTrack.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "FileDialog.h" #include "AudioEngine.h" #include "AutomationPattern.h" #include "BBTrack.h" -#include "CaptionMenu.h" -#include "ComboBox.h" #include "ConfigManager.h" #include "ControllerConnection.h" #include "DataFile.h" -#include "EffectChain.h" -#include "EffectRackView.h" -#include "embed.h" -#include "FileBrowser.h" -#include "FxLineLcdSpinBox.h" #include "FxMixer.h" -#include "FxMixerView.h" -#include "GuiApplication.h" -#include "InstrumentSoundShapingView.h" -#include "FadeButton.h" -#include "gui_templates.h" +#include "InstrumentTrackView.h" #include "Instrument.h" -#include "InstrumentFunctionViews.h" -#include "InstrumentMidiIOView.h" -#include "InstrumentMiscView.h" -#include "Knob.h" -#include "LcdSpinBox.h" -#include "LedCheckbox.h" -#include "LeftRightNav.h" -#include "lmms_constants.h" -#include "MainWindow.h" #include "MidiClient.h" -#include "MidiPortMenu.h" #include "MixHelpers.h" #include "Pattern.h" -#include "PluginFactory.h" -#include "PluginView.h" -#include "SamplePlayHandle.h" #include "Song.h" -#include "StringPairDrag.h" -#include "TrackContainerView.h" -#include "TrackLabelButton.h" -#include "MidiCCRackView.h" -const int INSTRUMENT_WIDTH = 254; -const int INSTRUMENT_HEIGHT = INSTRUMENT_WIDTH; -const int PIANO_HEIGHT = 80; - - -// #### IT: InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : Track( Track::InstrumentTrack, tc ), MidiEventProcessor(), @@ -1110,948 +1062,3 @@ void InstrumentTrack::autoAssignMidiDevice(bool assign) } } - -// #### ITV: - - - -InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tcv ) : - TrackView( _it, tcv ), - m_window( nullptr ), - m_lastPos( -1, -1 ) -{ - setAcceptDrops( true ); - setFixedHeight( 32 ); - - m_tlb = new TrackLabelButton( this, getTrackSettingsWidget() ); - m_tlb->setCheckable( true ); - m_tlb->setIcon( embed::getIconPixmap( "instrument_track" ) ); - m_tlb->move( 3, 1 ); - m_tlb->show(); - - connect( m_tlb, SIGNAL( toggled( bool ) ), - this, SLOT( toggleInstrumentWindow( bool ) ) ); - - connect( _it, SIGNAL( nameChanged() ), - m_tlb, SLOT( update() ) ); - - connect(ConfigManager::inst(), SIGNAL(valueChanged(QString, QString, QString)), - this, SLOT(handleConfigChange(QString, QString, QString))); - - // creation of widgets for track-settings-widget - int widgetWidth; - if( ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt() ) - { - widgetWidth = DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT; - } - else - { - widgetWidth = DEFAULT_SETTINGS_WIDGET_WIDTH; - } - - m_volumeKnob = new Knob( knobSmall_17, getTrackSettingsWidget(), - tr( "Volume" ) ); - m_volumeKnob->setVolumeKnob( true ); - m_volumeKnob->setModel( &_it->m_volumeModel ); - m_volumeKnob->setHintText( tr( "Volume:" ), "%" ); - m_volumeKnob->move( widgetWidth-2*24, 2 ); - m_volumeKnob->setLabel( tr( "VOL" ) ); - m_volumeKnob->show(); - - m_panningKnob = new Knob( knobSmall_17, getTrackSettingsWidget(), - tr( "Panning" ) ); - m_panningKnob->setModel( &_it->m_panningModel ); - m_panningKnob->setHintText(tr("Panning:"), "%"); - m_panningKnob->move( widgetWidth-24, 2 ); - m_panningKnob->setLabel( tr( "PAN" ) ); - m_panningKnob->show(); - - m_midiMenu = new QMenu( tr( "MIDI" ), this ); - - // sequenced MIDI? - if( !Engine::audioEngine()->midiClient()->isRaw() ) - { - _it->m_midiPort.m_readablePortsMenu = new MidiPortMenu( - MidiPort::Input ); - _it->m_midiPort.m_writablePortsMenu = new MidiPortMenu( - MidiPort::Output ); - _it->m_midiPort.m_readablePortsMenu->setModel( - &_it->m_midiPort ); - _it->m_midiPort.m_writablePortsMenu->setModel( - &_it->m_midiPort ); - m_midiInputAction = m_midiMenu->addMenu( - _it->m_midiPort.m_readablePortsMenu ); - m_midiOutputAction = m_midiMenu->addMenu( - _it->m_midiPort.m_writablePortsMenu ); - } - else - { - m_midiInputAction = m_midiMenu->addAction( "" ); - m_midiOutputAction = m_midiMenu->addAction( "" ); - m_midiInputAction->setCheckable( true ); - m_midiOutputAction->setCheckable( true ); - connect( m_midiInputAction, SIGNAL( changed() ), this, - SLOT( midiInSelected() ) ); - connect( m_midiOutputAction, SIGNAL( changed() ), this, - SLOT( midiOutSelected() ) ); - connect( &_it->m_midiPort, SIGNAL( modeChanged() ), - this, SLOT( midiConfigChanged() ) ); - } - - m_midiInputAction->setText( tr( "Input" ) ); - m_midiOutputAction->setText( tr( "Output" ) ); - - QAction *midiRackAction = m_midiMenu->addAction(tr("Open/Close MIDI CC Rack")); - midiRackAction->setIcon(embed::getIconPixmap("midi_cc_rack")); - connect(midiRackAction, SIGNAL(triggered()), - this, SLOT(toggleMidiCCRack())); - - m_activityIndicator = new FadeButton( QApplication::palette().color( QPalette::Active, - QPalette::Background), - QApplication::palette().color( QPalette::Active, - QPalette::BrightText ), - QApplication::palette().color( QPalette::Active, - QPalette::BrightText).darker(), - getTrackSettingsWidget() ); - m_activityIndicator->setGeometry( - widgetWidth-2*24-11, 2, 8, 28 ); - m_activityIndicator->show(); - connect( m_activityIndicator, SIGNAL( pressed() ), - this, SLOT( activityIndicatorPressed() ) ); - connect( m_activityIndicator, SIGNAL( released() ), - this, SLOT( activityIndicatorReleased() ) ); - connect( _it, SIGNAL( newNote() ), - m_activityIndicator, SLOT( activate() ) ); - connect( _it, SIGNAL( endNote() ), - m_activityIndicator, SLOT( noteEnd() ) ); - - setModel( _it ); -} - - - - -InstrumentTrackView::~InstrumentTrackView() -{ - delete m_window; - m_window = nullptr; - - delete model()->m_midiPort.m_readablePortsMenu; - delete model()->m_midiPort.m_writablePortsMenu; -} - - - - -void InstrumentTrackView::toggleMidiCCRack() -{ - // Lazy creation: midiCCRackView is only created when accessed the first time. - // this->model() returns pointer to the InstrumentTrack who owns this InstrumentTrackView. - if (!m_midiCCRackView) - { - m_midiCCRackView = std::unique_ptr(new MidiCCRackView(this->model())); - } - - if (m_midiCCRackView->parentWidget()->isVisible()) - { - m_midiCCRackView->parentWidget()->hide(); - } - else - { - m_midiCCRackView->parentWidget()->show(); - m_midiCCRackView->show(); - } -} - - - - -InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() -{ - InstrumentTrackWindow * w = nullptr; - for( const QMdiSubWindow * sw : - getGUI()->mainWindow()->workspace()->subWindowList( - QMdiArea::ActivationHistoryOrder ) ) - { - if( sw->isVisible() && sw->widget()->inherits( "InstrumentTrackWindow" ) ) - { - w = qobject_cast( sw->widget() ); - } - } - - return w; -} - - - - -/*! \brief Create and assign a new FX Channel for this track */ -void InstrumentTrackView::createFxLine() -{ - int channelIndex = getGUI()->fxMixerView()->addNewChannel(); - auto channel = Engine::fxMixer()->effectChannel(channelIndex); - - channel->m_name = getTrack()->name(); - if (getTrack()->useColor()) { channel->setColor (getTrack()->color()); } - - assignFxLine(channelIndex); -} - - - - -/*! \brief Assign a specific FX Channel for this track */ -void InstrumentTrackView::assignFxLine(int channelIndex) -{ - model()->effectChannelModel()->setValue( channelIndex ); - - getGUI()->fxMixerView()->setCurrentFxLine( channelIndex ); -} - - - -InstrumentTrackWindow * InstrumentTrackView::getInstrumentTrackWindow() -{ - if (!m_window) - { - m_window = new InstrumentTrackWindow(this); - } - - return m_window; -} - -void InstrumentTrackView::handleConfigChange(QString cls, QString attr, QString value) -{ - // When one instrument track window mode is turned on, - // close windows except last opened one. - if (cls == "ui" && attr == "oneinstrumenttrackwindow" && value.toInt()) - { - m_tlb->setChecked(m_window && m_window == topLevelInstrumentTrackWindow()); - } -} - -void InstrumentTrackView::dragEnterEvent( QDragEnterEvent * _dee ) -{ - InstrumentTrackWindow::dragEnterEventGeneric( _dee ); - if( !_dee->isAccepted() ) - { - TrackView::dragEnterEvent( _dee ); - } -} - - - - -void InstrumentTrackView::dropEvent( QDropEvent * _de ) -{ - getInstrumentTrackWindow()->dropEvent( _de ); - TrackView::dropEvent( _de ); -} - - - - -void InstrumentTrackView::toggleInstrumentWindow( bool _on ) -{ - if (_on && ConfigManager::inst()->value("ui", "oneinstrumenttrackwindow").toInt()) - { - if (topLevelInstrumentTrackWindow()) - { - topLevelInstrumentTrackWindow()->m_itv->m_tlb->setChecked(false); - } - } - - getInstrumentTrackWindow()->toggleVisibility( _on ); -} - - - - -void InstrumentTrackView::activityIndicatorPressed() -{ - model()->processInEvent( MidiEvent( MidiNoteOn, 0, DefaultKey, MidiDefaultVelocity ) ); -} - - - - -void InstrumentTrackView::activityIndicatorReleased() -{ - model()->processInEvent( MidiEvent( MidiNoteOff, 0, DefaultKey, 0 ) ); -} - - - - - -void InstrumentTrackView::midiInSelected() -{ - if( model() ) - { - model()->m_midiPort.setReadable( m_midiInputAction->isChecked() ); - } -} - - - - -void InstrumentTrackView::midiOutSelected() -{ - if( model() ) - { - model()->m_midiPort.setWritable( m_midiOutputAction->isChecked() ); - } -} - - - - -void InstrumentTrackView::midiConfigChanged() -{ - m_midiInputAction->setChecked( model()->m_midiPort.isReadable() ); - m_midiOutputAction->setChecked( model()->m_midiPort.isWritable() ); -} - - - - -//FIXME: This is identical to SampleTrackView::createFxMenu -QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) -{ - int channelIndex = model()->effectChannelModel()->value(); - - FxChannel *fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); - - // If title allows interpolation, pass channel index and name - if ( title.contains( "%2" ) ) - { - title = title.arg( channelIndex ).arg( fxChannel->m_name ); - } - - QMenu *fxMenu = new QMenu( title ); - - fxMenu->addAction( newFxLabel, this, SLOT( createFxLine() ) ); - fxMenu->addSeparator(); - - for (int i = 0; i < Engine::fxMixer()->numChannels(); ++i) - { - FxChannel * currentChannel = Engine::fxMixer()->effectChannel( i ); - - if ( currentChannel != fxChannel ) - { - auto index = currentChannel->m_channelIndex; - QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); - fxMenu->addAction(label, [this, index](){ - assignFxLine(index); - }); - } - } - - return fxMenu; -} - - - - -// #### ITW: -InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) : - QWidget(), - ModelView( nullptr, this ), - m_track( _itv->model() ), - m_itv( _itv ), - m_instrumentView( nullptr ) -{ - setAcceptDrops( true ); - - // init own layout + widgets - setFocusPolicy( Qt::StrongFocus ); - QVBoxLayout * vlayout = new QVBoxLayout( this ); - vlayout->setMargin( 0 ); - vlayout->setSpacing( 0 ); - - TabWidget* generalSettingsWidget = new TabWidget( tr( "GENERAL SETTINGS" ), this ); - - QVBoxLayout* generalSettingsLayout = new QVBoxLayout( generalSettingsWidget ); - - generalSettingsLayout->setContentsMargins( 8, 18, 8, 8 ); - generalSettingsLayout->setSpacing( 6 ); - - QWidget* nameAndChangeTrackWidget = new QWidget( generalSettingsWidget ); - QHBoxLayout* nameAndChangeTrackLayout = new QHBoxLayout( nameAndChangeTrackWidget ); - nameAndChangeTrackLayout->setContentsMargins( 0, 0, 0, 0 ); - nameAndChangeTrackLayout->setSpacing( 2 ); - - // setup line edit for changing instrument track name - m_nameLineEdit = new QLineEdit; - m_nameLineEdit->setFont( pointSize<9>( m_nameLineEdit->font() ) ); - connect( m_nameLineEdit, SIGNAL( textChanged( const QString & ) ), - this, SLOT( textChanged( const QString & ) ) ); - - m_nameLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); - nameAndChangeTrackLayout->addWidget(m_nameLineEdit, 1); - - - // set up left/right arrows for changing instrument - m_leftRightNav = new LeftRightNav(this); - connect( m_leftRightNav, SIGNAL( onNavLeft() ), this, - SLOT( viewPrevInstrument() ) ); - connect( m_leftRightNav, SIGNAL( onNavRight() ), this, - SLOT( viewNextInstrument() ) ); - // m_leftRightNav->setShortcuts(); - nameAndChangeTrackLayout->addWidget(m_leftRightNav); - - - generalSettingsLayout->addWidget( nameAndChangeTrackWidget ); - - - - QGridLayout* basicControlsLayout = new QGridLayout; - basicControlsLayout->setHorizontalSpacing(3); - basicControlsLayout->setVerticalSpacing(0); - basicControlsLayout->setContentsMargins(0, 0, 0, 0); - - QString labelStyleSheet = "font-size: 6pt;"; - Qt::Alignment labelAlignment = Qt::AlignHCenter | Qt::AlignTop; - Qt::Alignment widgetAlignment = Qt::AlignHCenter | Qt::AlignCenter; - - // set up volume knob - m_volumeKnob = new Knob( knobBright_26, nullptr, tr( "Volume" ) ); - m_volumeKnob->setVolumeKnob( true ); - m_volumeKnob->setHintText( tr( "Volume:" ), "%" ); - - basicControlsLayout->addWidget( m_volumeKnob, 0, 0 ); - basicControlsLayout->setAlignment( m_volumeKnob, widgetAlignment ); - - QLabel *label = new QLabel( tr( "VOL" ), this ); - label->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( label, 1, 0); - basicControlsLayout->setAlignment( label, labelAlignment ); - - - // set up panning knob - m_panningKnob = new Knob( knobBright_26, nullptr, tr( "Panning" ) ); - m_panningKnob->setHintText( tr( "Panning:" ), "" ); - - basicControlsLayout->addWidget( m_panningKnob, 0, 1 ); - basicControlsLayout->setAlignment( m_panningKnob, widgetAlignment ); - - label = new QLabel( tr( "PAN" ), this ); - label->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( label, 1, 1); - basicControlsLayout->setAlignment( label, labelAlignment ); - - - basicControlsLayout->setColumnStretch(2, 1); - - - // set up pitch knob - m_pitchKnob = new Knob( knobBright_26, nullptr, tr( "Pitch" ) ); - m_pitchKnob->setHintText( tr( "Pitch:" ), " " + tr( "cents" ) ); - - basicControlsLayout->addWidget( m_pitchKnob, 0, 3 ); - basicControlsLayout->setAlignment( m_pitchKnob, widgetAlignment ); - - m_pitchLabel = new QLabel( tr( "PITCH" ), this ); - m_pitchLabel->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( m_pitchLabel, 1, 3); - basicControlsLayout->setAlignment( m_pitchLabel, labelAlignment ); - - - // set up pitch range knob - m_pitchRangeSpinBox= new LcdSpinBox( 2, nullptr, tr( "Pitch range (semitones)" ) ); - - basicControlsLayout->addWidget( m_pitchRangeSpinBox, 0, 4 ); - basicControlsLayout->setAlignment( m_pitchRangeSpinBox, widgetAlignment ); - - m_pitchRangeLabel = new QLabel( tr( "RANGE" ), this ); - m_pitchRangeLabel->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( m_pitchRangeLabel, 1, 4); - basicControlsLayout->setAlignment( m_pitchRangeLabel, labelAlignment ); - - - basicControlsLayout->setColumnStretch(5, 1); - - - // setup spinbox for selecting FX-channel - m_effectChannelNumber = new FxLineLcdSpinBox( 2, nullptr, tr( "FX channel" ), m_itv ); - - basicControlsLayout->addWidget( m_effectChannelNumber, 0, 6 ); - basicControlsLayout->setAlignment( m_effectChannelNumber, widgetAlignment ); - - label = new QLabel( tr( "FX" ), this ); - label->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( label, 1, 6); - basicControlsLayout->setAlignment( label, labelAlignment ); - - QPushButton* saveSettingsBtn = new QPushButton( embed::getIconPixmap( "project_save" ), QString() ); - saveSettingsBtn->setMinimumSize( 32, 32 ); - - connect( saveSettingsBtn, SIGNAL( clicked() ), this, SLOT( saveSettingsBtnClicked() ) ); - - ToolTip::add( saveSettingsBtn, tr( "Save current instrument track settings in a preset file" ) ); - - basicControlsLayout->addWidget( saveSettingsBtn, 0, 7 ); - - label = new QLabel( tr( "SAVE" ), this ); - label->setStyleSheet( labelStyleSheet ); - basicControlsLayout->addWidget( label, 1, 7); - basicControlsLayout->setAlignment( label, labelAlignment ); - - generalSettingsLayout->addLayout( basicControlsLayout ); - - - m_tabWidget = new TabWidget( "", this, true, true ); - // "-1" : - // in "TabWidget::addTab", under "Position tab's window", the widget is - // moved up by 1 pixel - m_tabWidget->setMinimumHeight( INSTRUMENT_HEIGHT + GRAPHIC_TAB_HEIGHT - 4 - 1 ); - - - // create tab-widgets - m_ssView = new InstrumentSoundShapingView( m_tabWidget ); - - // FUNC tab - QWidget* instrumentFunctions = new QWidget( m_tabWidget ); - QVBoxLayout* instrumentFunctionsLayout = new QVBoxLayout( instrumentFunctions ); - instrumentFunctionsLayout->setMargin( 5 ); - m_noteStackingView = new InstrumentFunctionNoteStackingView( &m_track->m_noteStacking ); - m_arpeggioView = new InstrumentFunctionArpeggioView( &m_track->m_arpeggio ); - - instrumentFunctionsLayout->addWidget( m_noteStackingView ); - instrumentFunctionsLayout->addWidget( m_arpeggioView ); - instrumentFunctionsLayout->addStretch(); - - // MIDI tab - m_midiView = new InstrumentMidiIOView( m_tabWidget ); - - // FX tab - m_effectView = new EffectRackView( m_track->m_audioPort.effects(), m_tabWidget ); - - // MISC tab - m_miscView = new InstrumentMiscView( m_track, m_tabWidget ); - - - m_tabWidget->addTab( m_ssView, tr( "Envelope, filter & LFO" ), "env_lfo_tab", 1 ); - m_tabWidget->addTab( instrumentFunctions, tr( "Chord stacking & arpeggio" ), "func_tab", 2 ); - m_tabWidget->addTab( m_effectView, tr( "Effects" ), "fx_tab", 3 ); - m_tabWidget->addTab( m_midiView, tr( "MIDI" ), "midi_tab", 4 ); - m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 ); - adjustTabSize(m_ssView); - adjustTabSize(instrumentFunctions); - m_effectView->resize(EffectRackView::DEFAULT_WIDTH, INSTRUMENT_HEIGHT - 4 - 1); - adjustTabSize(m_midiView); - adjustTabSize(m_miscView); - - // setup piano-widget - m_pianoView = new PianoView( this ); - m_pianoView->setMinimumHeight( PIANO_HEIGHT ); - m_pianoView->setMaximumHeight( PIANO_HEIGHT ); - - vlayout->addWidget( generalSettingsWidget ); - // Use QWidgetItem explicitly to make the size hint change on instrument changes - // QLayout::addWidget() uses QWidgetItemV2 with size hint caching - vlayout->insertItem(1, new QWidgetItem(m_tabWidget)); - vlayout->addWidget( m_pianoView ); - setModel( _itv->model() ); - - QMdiSubWindow* subWin = getGUI()->mainWindow()->addWindowedWidget( this ); - Qt::WindowFlags flags = subWin->windowFlags(); - flags |= Qt::MSWindowsFixedSizeDialogHint; - flags &= ~Qt::WindowMaximizeButtonHint; - subWin->setWindowFlags( flags ); - - updateInstrumentView(); - - // Hide the Size and Maximize options from the system menu - // since the dialog size is fixed. - QMenu * systemMenu = subWin->systemMenu(); - systemMenu->actions().at( 2 )->setVisible( false ); // Size - systemMenu->actions().at( 4 )->setVisible( false ); // Maximize - - subWin->setWindowIcon( embed::getIconPixmap( "instrument_track" ) ); - subWin->setMinimumSize( subWin->size() ); - subWin->hide(); -} - - - - -InstrumentTrackWindow::~InstrumentTrackWindow() -{ - delete m_instrumentView; - - if (parentWidget()) - { - parentWidget()->hide(); - parentWidget()->deleteLater(); - } -} - - - - -void InstrumentTrackWindow::setInstrumentTrackView( InstrumentTrackView* view ) -{ - if( m_itv && view ) - { - m_itv->m_tlb->setChecked( false ); - } - - m_itv = view; - m_effectChannelNumber->setTrackView(m_itv); -} - - - - -void InstrumentTrackWindow::modelChanged() -{ - m_track = castModel(); - - m_nameLineEdit->setText( m_track->name() ); - - m_track->disconnect( SIGNAL( nameChanged() ), this ); - m_track->disconnect( SIGNAL( instrumentChanged() ), this ); - - connect( m_track, SIGNAL( nameChanged() ), - this, SLOT( updateName() ) ); - connect( m_track, SIGNAL( instrumentChanged() ), - this, SLOT( updateInstrumentView() ) ); - - m_volumeKnob->setModel( &m_track->m_volumeModel ); - m_panningKnob->setModel( &m_track->m_panningModel ); - m_effectChannelNumber->setModel( &m_track->m_effectChannelModel ); - m_pianoView->setModel( &m_track->m_piano ); - - if( m_track->instrument() && m_track->instrument()->flags().testFlag( Instrument::IsNotBendable ) == false ) - { - m_pitchKnob->setModel( &m_track->m_pitchModel ); - m_pitchRangeSpinBox->setModel( &m_track->m_pitchRangeModel ); - m_pitchKnob->show(); - m_pitchLabel->show(); - m_pitchRangeSpinBox->show(); - m_pitchRangeLabel->show(); - } - else - { - m_pitchKnob->hide(); - m_pitchLabel->hide(); - m_pitchKnob->setModel( nullptr ); - m_pitchRangeSpinBox->hide(); - m_pitchRangeLabel->hide(); - } - - if (m_track->instrument() && m_track->instrument()->flags().testFlag(Instrument::IsMidiBased)) - { - m_miscView->microtunerGroupBox()->hide(); - m_track->m_microtuner.enabledModel()->setValue(false); - } - else - { - m_miscView->microtunerGroupBox()->show(); - } - - m_ssView->setModel( &m_track->m_soundShaping ); - m_noteStackingView->setModel( &m_track->m_noteStacking ); - m_arpeggioView->setModel( &m_track->m_arpeggio ); - m_midiView->setModel( &m_track->m_midiPort ); - m_effectView->setModel( m_track->m_audioPort.effects() ); - m_miscView->pitchGroupBox()->setModel(&m_track->m_useMasterPitchModel); - m_miscView->microtunerGroupBox()->setModel(m_track->m_microtuner.enabledModel()); - m_miscView->scaleCombo()->setModel(m_track->m_microtuner.scaleModel()); - m_miscView->keymapCombo()->setModel(m_track->m_microtuner.keymapModel()); - m_miscView->rangeImportCheckbox()->setModel(m_track->m_microtuner.keyRangeImportModel()); - updateName(); -} - - - - -void InstrumentTrackWindow::saveSettingsBtnClicked() -{ - FileDialog sfd( this, tr( "Save preset" ), "", tr( "XML preset file (*.xpf)" ) ); - - QString presetRoot = ConfigManager::inst()->userPresetsDir(); - if( !QDir( presetRoot ).exists() ) - { - QDir().mkdir( presetRoot ); - } - if( !QDir( presetRoot + m_track->instrumentName() ).exists() ) - { - QDir( presetRoot ).mkdir( m_track->instrumentName() ); - } - - sfd.setAcceptMode( FileDialog::AcceptSave ); - sfd.setDirectory( presetRoot + m_track->instrumentName() ); - sfd.setFileMode( FileDialog::AnyFile ); - QString fname = m_track->name(); - sfd.selectFile(fname.remove(QRegExp(FILENAME_FILTER))); - sfd.setDefaultSuffix( "xpf"); - - if( sfd.exec() == QDialog::Accepted && - !sfd.selectedFiles().isEmpty() && - !sfd.selectedFiles().first().isEmpty() ) - { - DataFile dataFile( DataFile::InstrumentTrackSettings ); - m_track->setSimpleSerializing(); - m_track->saveSettings( dataFile, dataFile.content() ); - QString f = sfd.selectedFiles()[0]; - dataFile.writeFile( f ); - } -} - - - - - -void InstrumentTrackWindow::updateName() -{ - setWindowTitle( m_track->name().length() > 25 ? ( m_track->name().left(24)+"..." ) : m_track->name() ); - - if( m_nameLineEdit->text() != m_track->name() ) - { - m_nameLineEdit->setText( m_track->name() ); - } -} - - - - - -void InstrumentTrackWindow::updateInstrumentView() -{ - delete m_instrumentView; - if( m_track->m_instrument != nullptr ) - { - m_instrumentView = m_track->m_instrument->createView( m_tabWidget ); - m_tabWidget->addTab( m_instrumentView, tr( "Plugin" ), "plugin_tab", 0 ); - m_tabWidget->setActiveTab( 0 ); - - m_ssView->setFunctionsHidden( m_track->m_instrument->flags().testFlag( Instrument::IsSingleStreamed ) ); - - modelChanged(); // Get the instrument window to refresh - m_track->dataChanged(); // Get the text on the trackButton to change - - adjustTabSize(m_instrumentView); - m_pianoView->setVisible(m_track->m_instrument->hasNoteInput()); - // adjust window size - layout()->invalidate(); - resize(sizeHint()); - if (parentWidget()) - { - parentWidget()->resize(parentWidget()->sizeHint()); - } - update(); - m_instrumentView->update(); - } -} - - - - -void InstrumentTrackWindow::textChanged( const QString& newName ) -{ - m_track->setName( newName ); - Engine::getSong()->setModified(); -} - - - - -void InstrumentTrackWindow::toggleVisibility( bool on ) -{ - if( on ) - { - show(); - parentWidget()->show(); - parentWidget()->raise(); - } - else - { - parentWidget()->hide(); - } -} - - - - -void InstrumentTrackWindow::closeEvent( QCloseEvent* event ) -{ - event->ignore(); - - if( getGUI()->mainWindow()->workspace() ) - { - parentWidget()->hide(); - } - else - { - hide(); - } - - m_itv->m_tlb->setFocus(); - m_itv->m_tlb->setChecked( false ); -} - - - - -void InstrumentTrackWindow::focusInEvent( QFocusEvent* ) -{ - if(m_pianoView->isVisible()) { - m_pianoView->setFocus(); - } -} - - - - -void InstrumentTrackWindow::dragEnterEventGeneric( QDragEnterEvent* event ) -{ - StringPairDrag::processDragEnterEvent( event, "instrument,presetfile,pluginpresetfile" ); -} - - - - -void InstrumentTrackWindow::dragEnterEvent( QDragEnterEvent* event ) -{ - dragEnterEventGeneric( event ); -} - - - - -void InstrumentTrackWindow::dropEvent( QDropEvent* event ) -{ - QString type = StringPairDrag::decodeKey( event ); - QString value = StringPairDrag::decodeValue( event ); - - if( type == "instrument" ) - { - m_track->loadInstrument( value, nullptr, true /* DnD */ ); - - Engine::getSong()->setModified(); - - event->accept(); - setFocus(); - } - else if( type == "presetfile" ) - { - DataFile dataFile(value); - m_track->replaceInstrument(dataFile); - event->accept(); - setFocus(); - } - else if( type == "pluginpresetfile" ) - { - const QString ext = FileItem::extension( value ); - Instrument * i = m_track->instrument(); - - if( !i->descriptor()->supportsFileType( ext ) ) - { - PluginFactory::PluginInfoAndKey piakn = - getPluginFactory()->pluginSupportingExtension(ext); - i = m_track->loadInstrument(piakn.info.name(), &piakn.key); - } - - i->loadFile( value ); - - event->accept(); - setFocus(); - } -} - - - - -void InstrumentTrackWindow::saveSettings( QDomDocument& doc, QDomElement & thisElement ) -{ - thisElement.setAttribute( "tab", m_tabWidget->activeTab() ); - MainWindow::saveWidgetState( this, thisElement ); -} - - - - -void InstrumentTrackWindow::loadSettings( const QDomElement& thisElement ) -{ - m_tabWidget->setActiveTab( thisElement.attribute( "tab" ).toInt() ); - MainWindow::restoreWidgetState( this, thisElement ); - if( isVisible() ) - { - m_itv->m_tlb->setChecked( true ); - } -} - -void InstrumentTrackWindow::viewInstrumentInDirection(int d) -{ - // helper routine for viewNextInstrument, viewPrevInstrument - // d=-1 to view the previous instrument, - // d=+1 to view the next instrument - - const QList &trackViews = m_itv->trackContainerView()->trackViews(); - int idxOfMe = trackViews.indexOf(m_itv); - - // search for the next InstrumentTrackView (i.e. skip AutomationViews, etc) - // sometimes, the next InstrumentTrackView may already be open, in which case - // replace our window contents with the *next* closed Instrument Track and - // give focus to the InstrumentTrackView we skipped. - int idxOfNext = idxOfMe; - InstrumentTrackView *newView = nullptr; - InstrumentTrackView *bringToFront = nullptr; - do - { - idxOfNext = (idxOfNext + d + trackViews.size()) % trackViews.size(); - newView = dynamic_cast(trackViews[idxOfNext]); - // the window that should be brought to focus is the FIRST InstrumentTrackView that comes after us - if (bringToFront == nullptr && newView != nullptr) - { - bringToFront = newView; - } - // if the next instrument doesn't have an active window, then exit loop & load that one into our window. - if (newView != nullptr && !newView->m_tlb->isChecked()) - { - break; - } - } while (idxOfNext != idxOfMe); - - // avoid reloading the window if there is only one instrument, as that will just change the active tab - if (idxOfNext != idxOfMe) - { - // save current window pos and then hide the window by unchecking its button in the track list - QPoint curPos = parentWidget()->pos(); - m_itv->m_tlb->setChecked(false); - - // enable the new window by checking its track list button & moving it to where our window just was - newView->m_tlb->setChecked(true); - newView->getInstrumentTrackWindow()->parentWidget()->move(curPos); - - // scroll the SongEditor/BB-editor to make sure the new trackview label is visible - bringToFront->trackContainerView()->scrollToTrackView(bringToFront); - - // get the instrument window to refresh - modelChanged(); - } - Q_ASSERT(bringToFront); - bringToFront->getInstrumentTrackWindow()->setFocus(); -} - -void InstrumentTrackWindow::viewNextInstrument() -{ - viewInstrumentInDirection(+1); -} -void InstrumentTrackWindow::viewPrevInstrument() -{ - viewInstrumentInDirection(-1); -} - -void InstrumentTrackWindow::adjustTabSize(QWidget *w) -{ - // "-1" : - // in "TabWidget::addTab", under "Position tab's window", the widget is - // moved up by 1 pixel - w->setMinimumSize(INSTRUMENT_WIDTH - 4, INSTRUMENT_HEIGHT - 4 - 1); -} - -#include "InstrumentTrack.moc"