Use Qt layouts for mixer channels (#6591)

Use Qt layouts for the mixer channels. These changes will enable several other improvements, like for example making the mixer and faders resizable, adding peak indicators, etc.

This is a squash commit which consists of the following individual commits:

* Remove extra transparency in send/receive arrows
The extra transparency was conflicting with the positioning of
the arrows in the layout

* Begin reimplementing MixerChannelView

MixerChannelView is now a combination of the
MixerLine with the previous MixerChannelView

* Adjust SendButtonIndicator to use MixerChannelView

* Remove MixerLine
- Move MixerChannelView into src/gui

* Remove MixerView::MixerChannelView

* Remove header of MixerLine

* Change MixerView.h to use MixerChannelView
Change MixerView.h to use MixerChannelView rather than MixerLine
Also do some cleanup, such as removing an unused forward declaration
of QButtonGroup

* Create EffectRackView
+ Set height of sizeHint() using MIXER_CHANNEL_HEIGHT (287)

* Remove include of MixerLine
- Include MixerChannelView

* Phase 1: Adjust MixerView to use new MixerChannelView

* Move children wigets into header file

* Phase 2: Adjust MixerView to use new MixerChannelView

* Phase 3: Adjust MixerView to use new MixerChannelView

* Phase 4: Adjust MixerView to use new MixerChannelView

* Phase 5: Adjust MixerView to use new MixerChannelView

* Phase 5: Adjust MixerView to use new MixerChannelView

* Remove places where MixerChannelView is being deleted

Before, MixerChannelView was not inherited by QWidget,
meaning it could not have a parent and had to be deleted
when necessary. Since the MixerView owns the
new MixerChannelView, this is no longer necessary.

* Replace MixerLine with MixerChannelView
- Include MixerChannelView in MixerView

* Replace setCurrentMixerLine calls with setCurrentMixerChannel around codebase

* Add event handlers in MixerChannelView

* Implement MixerChannelView::eventFilter

* Update theme styles to use MixerChannelView

* Add QColor properties from style
- Set the Qt::WA_StyledBackground attribute on

* Add effect rack to rack layout when adding channel

* Set size for MixerChannelView
- Change nullptr to this for certain widgets
   - Some custom widgets may expect there to be a parent
- Add spacing in channel layout
- Increase size of mixer channel

* Retain size when widgets are hidden

* Implement paintEvent
- Rename states in SendReceiveState

* Implement send/receive arrow toggling
- Make maxTextHeight constexpr in elideName
- Remove background changing on mouse press
(is now handled in paintEvent)

* Implement renaming mixer channels

* Implement color functions

* Implement channel moving/removing functions

* Do some cleanup
Not sure if that connection with the mute model was needed, but removing
it did not seem to introduce any issues.

* Include cassert

* Replace references to MixerLine with MixerChannelView

* Reduce height
+ Make m_renameLineEdit transparent
+ Retain size when LCD is hidden
+ Remove stretch after renameLineEdit in layout

* Remove trailing whitespace

* Make m_renameLineEdit read only
+ Transpose m_renameLineEditView rectangle (with 5px offset)

* Set spacing in channel layout back to 0

* Remove sizeHint override and constant size

* Use sizeHint for mixerChannelSize
+ Leave auto fill background to false in MixerChannelView
+ Only set width for EffectRackView

* Set margins to 4 on all sides in MixerChannelView

* Move solo and mute closer to each other

Move the solo and mute buttons closer to each other in the mixer channels.

Technically this is accomplished by putting them into their own layout with minimal margins and spacing.

* Fixes for CodeFactor

* Code review changes

Mostly whitespace and formatting changes: remove tabs, remove spaces in parameter lists, remove underscores from parameter names.

Some lines have been shortened by introducing intermediate variables, e.g. in `MixerChannelView`.

`MixerView` has many changes but only related to whitespace. Spaces have been introduced for if and for statements. Whitespace at round braces has been removed everywhere in the implementation file even if a line was not touched by the intial changes.

Remove duplicate forward declaration of `MixerChannelView`.

* Adjust parameter order in MixerChannelView's constructor

Make the parent `QWidget` the first parameter as it is a Qt convention. The default parameter had to be removed due to this.

* Move styling of rename line edit into style sheets

Move the style of the `QGraphicsView` for the rename line edit from the code into the style sheets of the default and classic theme.

* More code review changes

Fix spaces between types and references/pointers, e.g. use `const QBrush& c` instead of `const QBrush & c`.
Remove underscores from parameter names.
Remove spaces near parentheses.
Replace tabs with spaces.
Introduce intermediate variable to resolve "hanging" + operator.
Replace the connection for the periodic fader updates with one that uses function pointers instead of `SIGNAL` and `SLOT`.

---------

Co-authored-by: Michael Gregorius <michael.gregorius.git@arcor.de>
This commit is contained in:
saker
2023-12-30 11:55:28 -05:00
committed by GitHub
parent 4e63f60652
commit 6b21dc7896
59 changed files with 1249 additions and 1325 deletions

View File

@@ -27,7 +27,7 @@ SET(LMMS_SRCS
gui/MicrotunerConfig.cpp
gui/MidiCCRackView.cpp
gui/MidiSetupWidget.cpp
gui/MixerLine.cpp
gui/MixerChannelView.cpp
gui/MixerView.cpp
gui/ModelView.cpp
gui/PeakControllerDialog.cpp
@@ -113,7 +113,7 @@ SET(LMMS_SRCS
gui/widgets/LedCheckBox.cpp
gui/widgets/LeftRightNav.cpp
gui/widgets/MeterDialog.cpp
gui/widgets/MixerLineLcdSpinBox.cpp
gui/widgets/MixerChannelLcdSpinBox.cpp
gui/widgets/NStateButton.cpp
gui/widgets/Oscilloscope.cpp
gui/widgets/PixmapButton.cpp

View File

@@ -0,0 +1,447 @@
/*
* MixerChannelView.h - the mixer channel view
*
* Copyright (c) 2022 saker <sakertooth@gmail.com>
*
* 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 "CaptionMenu.h"
#include "ColorChooser.h"
#include "GuiApplication.h"
#include "Mixer.h"
#include "MixerChannelView.h"
#include "MixerView.h"
#include "Song.h"
#include "gui_templates.h"
#include "lmms_math.h"
#include <QGraphicsProxyWidget>
#include <QGraphicsScene>
#include <QMenu>
#include <QPainter>
#include <QFont>
#include <cassert>
namespace lmms::gui
{
MixerChannelView::MixerChannelView(QWidget* parent, MixerView* mixerView, int channelIndex) :
QWidget(parent),
m_mixerView(mixerView),
m_channelIndex(channelIndex)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
auto retainSizeWhenHidden = [](QWidget* widget)
{
auto sizePolicy = widget->sizePolicy();
sizePolicy.setRetainSizeWhenHidden(true);
widget->setSizePolicy(sizePolicy);
};
m_sendButton = new SendButtonIndicator{this, this, mixerView};
retainSizeWhenHidden(m_sendButton);
m_sendKnob = new Knob{KnobType::Bright26, this, tr("Channel send amount")};
retainSizeWhenHidden(m_sendKnob);
m_channelNumberLcd = new LcdWidget{2, this};
m_channelNumberLcd->setValue(channelIndex);
retainSizeWhenHidden(m_channelNumberLcd);
const auto mixerChannel = Engine::mixer()->mixerChannel(channelIndex);
const auto mixerName = mixerChannel->m_name;
setToolTip(mixerName);
m_renameLineEdit = new QLineEdit{mixerName, nullptr};
m_renameLineEdit->setFixedWidth(65);
m_renameLineEdit->setFont(pointSizeF(font(), 7.5f));
m_renameLineEdit->setReadOnly(true);
m_renameLineEdit->installEventFilter(this);
auto renameLineEditScene = new QGraphicsScene{};
m_renameLineEditView = new QGraphicsView{};
m_renameLineEditView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_renameLineEditView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_renameLineEditView->setAttribute(Qt::WA_TransparentForMouseEvents, true);
m_renameLineEditView->setScene(renameLineEditScene);
auto renameLineEditProxy = renameLineEditScene->addWidget(m_renameLineEdit);
renameLineEditProxy->setRotation(-90);
m_renameLineEditView->setFixedSize(m_renameLineEdit->height() + 5, m_renameLineEdit->width() + 5);
m_sendArrow = new QLabel{};
m_sendArrow->setPixmap(embed::getIconPixmap("send_bg_arrow"));
retainSizeWhenHidden(m_sendArrow);
m_sendArrow->setVisible(m_sendReceiveState == SendReceiveState::SendToThis);
m_receiveArrow = new QLabel{};
m_receiveArrow->setPixmap(embed::getIconPixmap("receive_bg_arrow"));
retainSizeWhenHidden(m_receiveArrow);
m_receiveArrow->setVisible(m_sendReceiveState == SendReceiveState::ReceiveFromThis);
m_muteButton = new PixmapButton(this, tr("Mute"));
m_muteButton->setModel(&mixerChannel->m_muteModel);
m_muteButton->setActiveGraphic(embed::getIconPixmap("led_off"));
m_muteButton->setInactiveGraphic(embed::getIconPixmap("led_green"));
m_muteButton->setCheckable(true);
m_muteButton->setToolTip(tr("Mute this channel"));
m_soloButton = new PixmapButton(this, tr("Solo"));
m_soloButton->setModel(&mixerChannel->m_soloModel);
m_soloButton->setActiveGraphic(embed::getIconPixmap("led_red"));
m_soloButton->setInactiveGraphic(embed::getIconPixmap("led_off"));
m_soloButton->setCheckable(true);
m_soloButton->setToolTip(tr("Solo this channel"));
connect(&mixerChannel->m_soloModel, &BoolModel::dataChanged, mixerView, &MixerView::toggledSolo, Qt::DirectConnection);
QVBoxLayout* soloMuteLayout = new QVBoxLayout();
soloMuteLayout->setContentsMargins(0, 0, 0, 0);
soloMuteLayout->setSpacing(0);
soloMuteLayout->addWidget(m_soloButton, 0, Qt::AlignHCenter);
soloMuteLayout->addWidget(m_muteButton, 0, Qt::AlignHCenter);
m_fader = new Fader{&mixerChannel->m_volumeModel, tr("Fader %1").arg(channelIndex), this};
m_fader->setLevelsDisplayedInDBFS();
m_fader->setMinPeak(dbfsToAmp(-42));
m_fader->setMaxPeak(dbfsToAmp(9));
m_effectRackView = new EffectRackView{&mixerChannel->m_fxChain, mixerView->m_racksWidget};
m_effectRackView->setFixedWidth(EffectRackView::DEFAULT_WIDTH);
auto mainLayout = new QVBoxLayout{this};
mainLayout->setContentsMargins(4, 4, 4, 4);
mainLayout->addWidget(m_receiveArrow, 0, Qt::AlignHCenter);
mainLayout->addWidget(m_sendButton, 0, Qt::AlignHCenter);
mainLayout->addWidget(m_sendKnob, 0, Qt::AlignHCenter);
mainLayout->addWidget(m_sendArrow, 0, Qt::AlignHCenter);
mainLayout->addWidget(m_channelNumberLcd, 0, Qt::AlignHCenter);
mainLayout->addStretch();
mainLayout->addWidget(m_renameLineEditView, 0, Qt::AlignHCenter);
mainLayout->addLayout(soloMuteLayout, 0);
mainLayout->addWidget(m_fader, 0, Qt::AlignHCenter);
connect(m_renameLineEdit, &QLineEdit::editingFinished, this, &MixerChannelView::renameFinished);
}
void MixerChannelView::contextMenuEvent(QContextMenuEvent*)
{
auto contextMenu = new CaptionMenu(Engine::mixer()->mixerChannel(m_channelIndex)->m_name, this);
if (m_channelIndex != 0) // no move-options in master
{
contextMenu->addAction(tr("Move &left"), this, &MixerChannelView::moveChannelLeft);
contextMenu->addAction(tr("Move &right"), this, &MixerChannelView::moveChannelRight);
}
contextMenu->addAction(tr("Rename &channel"), this, &MixerChannelView::renameChannel);
contextMenu->addSeparator();
if (m_channelIndex != 0) // no remove-option in master
{
contextMenu->addAction(embed::getIconPixmap("cancel"), tr("R&emove channel"), this, &MixerChannelView::removeChannel);
contextMenu->addSeparator();
}
contextMenu->addAction(embed::getIconPixmap("cancel"), tr("Remove &unused channels"), this, &MixerChannelView::removeUnusedChannels);
contextMenu->addSeparator();
auto colorMenu = QMenu{tr("Color"), this};
colorMenu.setIcon(embed::getIconPixmap("colorize"));
colorMenu.addAction(tr("Change"), this, &MixerChannelView::selectColor);
colorMenu.addAction(tr("Reset"), this, &MixerChannelView::resetColor);
colorMenu.addAction(tr("Pick random"), this, &MixerChannelView::randomizeColor);
contextMenu->addMenu(&colorMenu);
contextMenu->exec(QCursor::pos());
delete contextMenu;
}
void MixerChannelView::paintEvent(QPaintEvent* event)
{
auto * mixer = Engine::mixer();
const auto channel = mixer->mixerChannel(m_channelIndex);
const bool muted = channel->m_muteModel.value();
const auto name = channel->m_name;
const auto elidedName = elideName(name);
const auto * mixerChannelView = m_mixerView->currentMixerChannel();
const auto isActive = mixerChannelView == this;
if (!m_inRename && m_renameLineEdit->text() != elidedName)
{
m_renameLineEdit->setText(elidedName);
}
const auto width = rect().width();
const auto height = rect().height();
auto painter = QPainter{this};
if (channel->color().has_value() && !muted)
{
painter.fillRect(rect(), channel->color()->darker(isActive ? 120 : 150));
}
else
{
painter.fillRect(rect(), isActive ? backgroundActive().color() : painter.background().color());
}
// inner border
painter.setPen(isActive ? strokeInnerActive() : strokeInnerInactive());
painter.drawRect(1, 1, width - MIXER_CHANNEL_INNER_BORDER_SIZE, height - MIXER_CHANNEL_INNER_BORDER_SIZE);
// outer border
painter.setPen(isActive ? strokeOuterActive() : strokeOuterInactive());
painter.drawRect(0, 0, width - MIXER_CHANNEL_OUTER_BORDER_SIZE, height - MIXER_CHANNEL_OUTER_BORDER_SIZE);
const auto & currentMixerChannelIndex = mixerChannelView->m_channelIndex;
const auto sendToThis = mixer->channelSendModel(currentMixerChannelIndex, m_channelIndex) != nullptr;
const auto receiveFromThis = mixer->channelSendModel(m_channelIndex, currentMixerChannelIndex) != nullptr;
const auto sendReceiveStateNone = !sendToThis && !receiveFromThis;
// Only one or none of them can be on
assert(sendToThis ^ receiveFromThis || sendReceiveStateNone);
m_sendArrow->setVisible(sendToThis);
m_receiveArrow->setVisible(receiveFromThis);
if (sendReceiveStateNone)
{
setSendReceiveState(SendReceiveState::None);
}
else
{
setSendReceiveState(sendToThis ? SendReceiveState::SendToThis : SendReceiveState::ReceiveFromThis);
}
QWidget::paintEvent(event);
}
void MixerChannelView::mousePressEvent(QMouseEvent*)
{
if (m_mixerView->currentMixerChannel() != this)
{
m_mixerView->setCurrentMixerChannel(this);
}
}
void MixerChannelView::mouseDoubleClickEvent(QMouseEvent*)
{
renameChannel();
}
bool MixerChannelView::eventFilter(QObject* dist, QEvent* event)
{
// If we are in a rename, capture the enter/return events and handle them
if (event->type() == QEvent::KeyPress)
{
auto keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
{
if (m_inRename)
{
renameFinished();
event->accept(); // Stop the event from propagating
return true;
}
}
}
return false;
}
int MixerChannelView::channelIndex() const
{
return m_channelIndex;
}
void MixerChannelView::setChannelIndex(int index)
{
MixerChannel* mixerChannel = Engine::mixer()->mixerChannel(index);
m_fader->setModel(&mixerChannel->m_volumeModel);
m_muteButton->setModel(&mixerChannel->m_muteModel);
m_soloButton->setModel(&mixerChannel->m_soloModel);
m_effectRackView->setModel(&mixerChannel->m_fxChain);
m_channelIndex = index;
}
MixerChannelView::SendReceiveState MixerChannelView::sendReceiveState() const
{
return m_sendReceiveState;
}
void MixerChannelView::setSendReceiveState(const SendReceiveState& state)
{
m_sendReceiveState = state;
m_sendArrow->setVisible(state == SendReceiveState::SendToThis);
m_receiveArrow->setVisible(state == SendReceiveState::ReceiveFromThis);
}
QBrush MixerChannelView::backgroundActive() const
{
return m_backgroundActive;
}
void MixerChannelView::setBackgroundActive(const QBrush& c)
{
m_backgroundActive = c;
}
QColor MixerChannelView::strokeOuterActive() const
{
return m_strokeOuterActive;
}
void MixerChannelView::setStrokeOuterActive(const QColor& c)
{
m_strokeOuterActive = c;
}
QColor MixerChannelView::strokeOuterInactive() const
{
return m_strokeOuterInactive;
}
void MixerChannelView::setStrokeOuterInactive(const QColor& c)
{
m_strokeOuterInactive = c;
}
QColor MixerChannelView::strokeInnerActive() const
{
return m_strokeInnerActive;
}
void MixerChannelView::setStrokeInnerActive(const QColor& c)
{
m_strokeInnerActive = c;
}
QColor MixerChannelView::strokeInnerInactive() const
{
return m_strokeInnerInactive;
}
void MixerChannelView::setStrokeInnerInactive(const QColor& c)
{
m_strokeInnerInactive = c;
}
void MixerChannelView::renameChannel()
{
m_inRename = true;
setToolTip("");
m_renameLineEdit->setReadOnly(false);
m_channelNumberLcd->hide();
m_renameLineEdit->setFixedWidth(m_renameLineEdit->width());
m_renameLineEdit->setText(Engine::mixer()->mixerChannel(m_channelIndex)->m_name);
m_renameLineEditView->setFocus();
m_renameLineEdit->selectAll();
m_renameLineEdit->setFocus();
}
void MixerChannelView::renameFinished()
{
m_inRename = false;
m_renameLineEdit->deselect();
m_renameLineEdit->setReadOnly(true);
m_renameLineEdit->setFixedWidth(m_renameLineEdit->width());
m_channelNumberLcd->show();
auto newName = m_renameLineEdit->text();
setFocus();
const auto mixerChannel = Engine::mixer()->mixerChannel(m_channelIndex);
if (!newName.isEmpty() && mixerChannel->m_name != newName)
{
mixerChannel->m_name = newName;
m_renameLineEdit->setText(elideName(newName));
Engine::getSong()->setModified();
}
setToolTip(mixerChannel->m_name);
}
void MixerChannelView::resetColor()
{
Engine::mixer()->mixerChannel(m_channelIndex)->setColor(std::nullopt);
Engine::getSong()->setModified();
update();
}
void MixerChannelView::selectColor()
{
const auto channel = Engine::mixer()->mixerChannel(m_channelIndex);
const auto initialColor = channel->color().value_or(backgroundActive().color());
const auto * colorChooser = ColorChooser{this}.withPalette(ColorChooser::Palette::Mixer);
const auto newColor = colorChooser->getColor(initialColor);
if (!newColor.isValid()) { return; }
channel->setColor(newColor);
Engine::getSong()->setModified();
update();
}
void MixerChannelView::randomizeColor()
{
auto channel = Engine::mixer()->mixerChannel(m_channelIndex);
channel->setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[rand() % 48]);
Engine::getSong()->setModified();
update();
}
void MixerChannelView::removeChannel()
{
auto mix = getGUI()->mixerView();
mix->deleteChannel(m_channelIndex);
}
void MixerChannelView::removeUnusedChannels()
{
auto mix = getGUI()->mixerView();
mix->deleteUnusedChannels();
}
void MixerChannelView::moveChannelLeft()
{
auto mix = getGUI()->mixerView();
mix->moveChannelLeft(m_channelIndex);
}
void MixerChannelView::moveChannelRight()
{
auto mix = getGUI()->mixerView();
mix->moveChannelRight(m_channelIndex);
}
QString MixerChannelView::elideName(const QString& name)
{
const auto maxTextHeight = m_renameLineEdit->width();
const auto metrics = QFontMetrics{m_renameLineEdit->font()};
const auto elidedName = metrics.elidedText(name, Qt::ElideRight, maxTextHeight);
return elidedName;
}
} // namespace lmms::gui

View File

@@ -1,448 +0,0 @@
/*
* MixerLine.cpp - Mixer line widget
*
* Copyright (c) 2009 Andrew Kelley <superjoe30/at/gmail/dot/com>
* Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 "MixerLine.h"
#include <cstdlib>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QLineEdit>
#include <QPainter>
#include "CaptionMenu.h"
#include "ColorChooser.h"
#include "embed.h"
#include "Knob.h"
#include "LcdWidget.h"
#include "Mixer.h"
#include "MixerView.h"
#include "gui_templates.h"
#include "GuiApplication.h"
#include "SendButtonIndicator.h"
#include "Song.h"
namespace lmms::gui
{
bool MixerLine::eventFilter( QObject *dist, QEvent *event )
{
// If we are in a rename, capture the enter/return events and handle them
if ( event->type() == QEvent::KeyPress )
{
auto keyEvent = static_cast<QKeyEvent*>(event);
if( keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
{
if( m_inRename )
{
renameFinished();
event->accept(); // Stop the event from propagating
return true;
}
}
}
return false;
}
const int MixerLine::MixerLineHeight = 287;
MixerLine::MixerLine( QWidget * _parent, MixerView * _mv, int _channelIndex ) :
QWidget( _parent ),
m_mv( _mv ),
m_channelIndex( _channelIndex ),
m_backgroundActive( Qt::SolidPattern ),
m_strokeOuterActive( 0, 0, 0 ),
m_strokeOuterInactive( 0, 0, 0 ),
m_strokeInnerActive( 0, 0, 0 ),
m_strokeInnerInactive( 0, 0, 0 ),
m_inRename( false )
{
setFixedSize( 33, MixerLineHeight );
setAttribute( Qt::WA_OpaquePaintEvent, true );
setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) );
// mixer sends knob
m_sendKnob = new Knob( KnobType::Bright26, this, tr( "Channel send amount" ) );
m_sendKnob->move( 3, 22 );
m_sendKnob->setVisible( false );
// send button indicator
m_sendBtn = new SendButtonIndicator( this, this, m_mv );
m_sendBtn->move( 2, 2 );
// channel number
m_lcd = new LcdWidget( 2, this );
m_lcd->setValue( m_channelIndex );
m_lcd->move( 4, 58 );
m_lcd->setMarginWidth( 1 );
QString name = Engine::mixer()->mixerChannel( m_channelIndex )->m_name;
setToolTip( name );
m_renameLineEdit = new QLineEdit();
m_renameLineEdit->setText( name );
m_renameLineEdit->setFixedWidth( 65 );
m_renameLineEdit->setFont( pointSizeF( font(), 7.5f ) );
m_renameLineEdit->setReadOnly( true );
m_renameLineEdit->installEventFilter( this );
auto scene = new QGraphicsScene();
scene->setSceneRect( 0, 0, 33, MixerLineHeight );
m_view = new QGraphicsView( this );
m_view->setStyleSheet( "border-style: none; background: transparent;" );
m_view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
m_view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
m_view->setAttribute( Qt::WA_TransparentForMouseEvents, true );
m_view->setScene( scene );
QGraphicsProxyWidget * proxyWidget = scene->addWidget( m_renameLineEdit );
proxyWidget->setRotation( -90 );
proxyWidget->setPos( 8, 145 );
connect( m_renameLineEdit, SIGNAL(editingFinished()), this, SLOT(renameFinished()));
connect( &Engine::mixer()->mixerChannel( m_channelIndex )->m_muteModel, SIGNAL(dataChanged()), this, SLOT(update()));
}
MixerLine::~MixerLine()
{
delete m_sendKnob;
delete m_sendBtn;
delete m_lcd;
}
void MixerLine::setChannelIndex( int index )
{
m_channelIndex = index;
m_lcd->setValue( m_channelIndex );
m_lcd->update();
}
void MixerLine::drawMixerLine( QPainter* p, const MixerLine *mixerLine, bool isActive, bool sendToThis, bool receiveFromThis )
{
auto channel = Engine::mixer()->mixerChannel( m_channelIndex );
bool muted = channel->m_muteModel.value();
QString name = channel->m_name;
QString elidedName = elideName( name );
if( !m_inRename && m_renameLineEdit->text() != elidedName )
{
m_renameLineEdit->setText( elidedName );
}
int width = mixerLine->rect().width();
int height = mixerLine->rect().height();
if (channel->color().has_value() && !muted)
{
p->fillRect(mixerLine->rect(), channel->color()->darker(isActive ? 120 : 150));
}
else
{
p->fillRect( mixerLine->rect(),
isActive ? mixerLine->backgroundActive().color() : p->background().color() );
}
// inner border
p->setPen( isActive ? mixerLine->strokeInnerActive() : mixerLine->strokeInnerInactive() );
p->drawRect( 1, 1, width-3, height-3 );
// outer border
p->setPen( isActive ? mixerLine->strokeOuterActive() : mixerLine->strokeOuterInactive() );
p->drawRect( 0, 0, width-1, height-1 );
// draw the mixer send background
static auto s_sendBgArrow = embed::getIconPixmap("send_bg_arrow", 29, 56);
static auto s_receiveBgArrow = embed::getIconPixmap("receive_bg_arrow", 29, 56);
p->drawPixmap(2, 0, 29, 56, sendToThis ? s_sendBgArrow : s_receiveBgArrow);
}
QString MixerLine::elideName( const QString & name )
{
const int maxTextHeight = 60;
QFontMetrics metrics( m_renameLineEdit->font() );
QString elidedName = metrics.elidedText( name, Qt::ElideRight, maxTextHeight );
return elidedName;
}
void MixerLine::paintEvent( QPaintEvent * )
{
bool sendToThis = Engine::mixer()->channelSendModel( m_mv->currentMixerLine()->m_channelIndex, m_channelIndex ) != nullptr;
bool receiveFromThis = Engine::mixer()->channelSendModel( m_channelIndex, m_mv->currentMixerLine()->m_channelIndex ) != nullptr;
QPainter painter;
painter.begin( this );
drawMixerLine( &painter, this, m_mv->currentMixerLine() == this, sendToThis, receiveFromThis );
painter.end();
}
void MixerLine::mousePressEvent( QMouseEvent * )
{
m_mv->setCurrentMixerLine( this );
}
void MixerLine::mouseDoubleClickEvent( QMouseEvent * )
{
renameChannel();
}
void MixerLine::contextMenuEvent( QContextMenuEvent * )
{
QPointer<CaptionMenu> contextMenu = new CaptionMenu( Engine::mixer()->mixerChannel( m_channelIndex )->m_name, this );
if( m_channelIndex != 0 ) // no move-options in master
{
contextMenu->addAction( tr( "Move &left" ), this, SLOT(moveChannelLeft()));
contextMenu->addAction( tr( "Move &right" ), this, SLOT(moveChannelRight()));
}
contextMenu->addAction( tr( "Rename &channel" ), this, SLOT(renameChannel()));
contextMenu->addSeparator();
if( m_channelIndex != 0 ) // no remove-option in master
{
contextMenu->addAction( embed::getIconPixmap( "cancel" ), tr( "R&emove channel" ), this, SLOT(removeChannel()));
contextMenu->addSeparator();
}
contextMenu->addAction( embed::getIconPixmap( "cancel" ), tr( "Remove &unused channels" ), this, SLOT(removeUnusedChannels()));
contextMenu->addSeparator();
QMenu colorMenu(tr("Color"), this);
colorMenu.setIcon(embed::getIconPixmap("colorize"));
colorMenu.addAction(tr("Change"), this, SLOT(selectColor()));
colorMenu.addAction(tr("Reset"), this, SLOT(resetColor()));
colorMenu.addAction(tr("Pick random"), this, SLOT(randomizeColor()));
contextMenu->addMenu(&colorMenu);
contextMenu->exec( QCursor::pos() );
delete contextMenu;
}
void MixerLine::renameChannel()
{
m_inRename = true;
setToolTip( "" );
m_renameLineEdit->setReadOnly( false );
m_lcd->hide();
m_renameLineEdit->setFixedWidth( 135 );
m_renameLineEdit->setText( Engine::mixer()->mixerChannel( m_channelIndex )->m_name );
m_view->setFocus();
m_renameLineEdit->selectAll();
m_renameLineEdit->setFocus();
}
void MixerLine::renameFinished()
{
m_inRename = false;
m_renameLineEdit->deselect();
m_renameLineEdit->setReadOnly( true );
m_renameLineEdit->setFixedWidth( 65 );
m_lcd->show();
QString newName = m_renameLineEdit->text();
setFocus();
if( !newName.isEmpty() && Engine::mixer()->mixerChannel( m_channelIndex )->m_name != newName )
{
Engine::mixer()->mixerChannel( m_channelIndex )->m_name = newName;
m_renameLineEdit->setText( elideName( newName ) );
Engine::getSong()->setModified();
}
QString name = Engine::mixer()->mixerChannel( m_channelIndex )->m_name;
setToolTip( name );
}
void MixerLine::removeChannel()
{
MixerView * mix = getGUI()->mixerView();
mix->deleteChannel( m_channelIndex );
}
void MixerLine::removeUnusedChannels()
{
MixerView * mix = getGUI()->mixerView();
mix->deleteUnusedChannels();
}
void MixerLine::moveChannelLeft()
{
MixerView * mix = getGUI()->mixerView();
mix->moveChannelLeft( m_channelIndex );
}
void MixerLine::moveChannelRight()
{
MixerView * mix = getGUI()->mixerView();
mix->moveChannelRight( m_channelIndex );
}
QBrush MixerLine::backgroundActive() const
{
return m_backgroundActive;
}
void MixerLine::setBackgroundActive( const QBrush & c )
{
m_backgroundActive = c;
}
QColor MixerLine::strokeOuterActive() const
{
return m_strokeOuterActive;
}
void MixerLine::setStrokeOuterActive( const QColor & c )
{
m_strokeOuterActive = c;
}
QColor MixerLine::strokeOuterInactive() const
{
return m_strokeOuterInactive;
}
void MixerLine::setStrokeOuterInactive( const QColor & c )
{
m_strokeOuterInactive = c;
}
QColor MixerLine::strokeInnerActive() const
{
return m_strokeInnerActive;
}
void MixerLine::setStrokeInnerActive( const QColor & c )
{
m_strokeInnerActive = c;
}
QColor MixerLine::strokeInnerInactive() const
{
return m_strokeInnerInactive;
}
void MixerLine::setStrokeInnerInactive( const QColor & c )
{
m_strokeInnerInactive = c;
}
// Ask user for a color, and set it as the mixer line color
void MixerLine::selectColor()
{
const auto channel = Engine::mixer()->mixerChannel(m_channelIndex);
const auto newColor = ColorChooser{this}
.withPalette(ColorChooser::Palette::Mixer)
->getColor(channel->color().value_or(backgroundActive().color()));
if (!newColor.isValid()) { return; }
channel->setColor(newColor);
Engine::getSong()->setModified();
update();
}
// Disable the usage of color on this mixer line
void MixerLine::resetColor()
{
Engine::mixer()->mixerChannel(m_channelIndex)->setColor(std::nullopt);
Engine::getSong()->setModified();
update();
}
// Pick a random color from the mixer palette and set it as our color
void MixerLine::randomizeColor()
{
const auto channel = Engine::mixer()->mixerChannel(m_channelIndex);
channel->setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[std::rand() % 48]);
Engine::getSong()->setModified();
update();
}
} // namespace lmms::gui

View File

@@ -33,9 +33,9 @@
#include "lmms_math.h"
#include "MixerChannelView.h"
#include "MixerView.h"
#include "Knob.h"
#include "MixerLine.h"
#include "Mixer.h"
#include "GuiApplication.h"
#include "MainWindow.h"
@@ -54,7 +54,7 @@ namespace lmms::gui
MixerView::MixerView() :
QWidget(),
ModelView( nullptr, this ),
ModelView(nullptr, this),
SerializingObjectHook()
{
#if QT_VERSION < 0x50C00
@@ -68,54 +68,54 @@ MixerView::MixerView() :
#endif
Mixer * m = Engine::mixer();
m->setHook( this );
m->setHook(this);
//QPalette pal = palette();
//pal.setColor( QPalette::Window, QColor( 72, 76, 88 ) );
//setPalette( pal );
//pal.setColor(QPalette::Window, QColor(72, 76, 88));
//setPalette(pal);
setAutoFillBackground( true );
setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
setAutoFillBackground(true);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
setWindowTitle( tr( "Mixer" ) );
setWindowIcon( embed::getIconPixmap( "mixer" ) );
setWindowTitle(tr("Mixer"));
setWindowIcon(embed::getIconPixmap("mixer"));
// main-layout
auto ml = new QHBoxLayout;
auto ml = new QHBoxLayout{this};
// Set margins
ml->setContentsMargins( 0, 4, 0, 0 );
ml->setContentsMargins(0, 4, 0, 0);
// Channel area
m_channelAreaWidget = new QWidget;
chLayout = new QHBoxLayout( m_channelAreaWidget );
chLayout->setSizeConstraint( QLayout::SetMinimumSize );
chLayout->setSpacing( 0 );
chLayout = new QHBoxLayout(m_channelAreaWidget);
chLayout->setSizeConstraint(QLayout::SetMinimumSize);
chLayout->setSpacing(0);
chLayout->setContentsMargins(0, 0, 0, 0);
m_channelAreaWidget->setLayout(chLayout);
// create rack layout before creating the first channel
m_racksWidget = new QWidget;
m_racksLayout = new QStackedLayout( m_racksWidget );
m_racksLayout->setContentsMargins( 0, 0, 0, 0 );
m_racksWidget->setLayout( m_racksLayout );
m_racksLayout = new QStackedLayout(m_racksWidget);
m_racksLayout->setContentsMargins(0, 0, 0, 0);
m_racksWidget->setLayout(m_racksLayout);
// add master channel
m_mixerChannelViews.resize( m->numChannels() );
m_mixerChannelViews[0] = new MixerChannelView( this, this, 0 );
m_mixerChannelViews.resize(m->numChannels());
m_mixerChannelViews[0] = new MixerChannelView(this, this, 0);
m_racksLayout->addWidget( m_mixerChannelViews[0]->m_rackView );
m_racksLayout->addWidget(m_mixerChannelViews[0]->m_effectRackView);
MixerChannelView * masterView = m_mixerChannelViews[0];
ml->addWidget( masterView->m_mixerLine, 0, Qt::AlignTop );
ml->addWidget(masterView, 0, Qt::AlignTop);
QSize mixerLineSize = masterView->m_mixerLine->size();
auto mixerChannelSize = masterView->sizeHint();
// add mixer channels
for( int i = 1; i < m_mixerChannelViews.size(); ++i )
for (int i = 1; i < m_mixerChannelViews.size(); ++i)
{
m_mixerChannelViews[i] = new MixerChannelView(m_channelAreaWidget, this, i);
chLayout->addWidget( m_mixerChannelViews[i]->m_mixerLine );
chLayout->addWidget(m_mixerChannelViews[i]);
}
// add the scrolling section to the main layout
@@ -123,68 +123,63 @@ MixerView::MixerView() :
class ChannelArea : public QScrollArea
{
public:
ChannelArea( QWidget * parent, MixerView * mv ) :
QScrollArea( parent ), m_mv( mv ) {}
ChannelArea(QWidget* parent, MixerView* mv) :
QScrollArea(parent), m_mv(mv) {}
~ChannelArea() override = default;
void keyPressEvent( QKeyEvent * e ) override
void keyPressEvent(QKeyEvent* e) override
{
m_mv->keyPressEvent( e );
m_mv->keyPressEvent(e);
}
private:
MixerView * m_mv;
MixerView* m_mv;
};
channelArea = new ChannelArea( this, this );
channelArea->setWidget( m_channelAreaWidget );
channelArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
channelArea->setFrameStyle( QFrame::NoFrame );
channelArea->setMinimumWidth( mixerLineSize.width() * 6 );
channelArea->setFixedHeight( mixerLineSize.height() +
style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
ml->addWidget( channelArea, 1, Qt::AlignTop );
channelArea = new ChannelArea(this, this);
channelArea->setWidget(m_channelAreaWidget);
channelArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
channelArea->setFrameStyle(QFrame::NoFrame);
channelArea->setMinimumWidth(mixerChannelSize.width() * 6);
int const scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
channelArea->setFixedHeight(mixerChannelSize.height() + scrollBarExtent);
ml->addWidget(channelArea, 1, Qt::AlignTop);
// show the add new mixer channel button
auto newChannelBtn = new QPushButton(embed::getIconPixmap("new_channel"), QString(), this);
newChannelBtn->setObjectName( "newChannelBtn" );
newChannelBtn->setFixedSize( mixerLineSize );
connect( newChannelBtn, SIGNAL(clicked()), this, SLOT(addNewChannel()));
ml->addWidget( newChannelBtn, 0, Qt::AlignTop );
newChannelBtn->setObjectName("newChannelBtn");
newChannelBtn->setFixedSize(mixerChannelSize);
connect(newChannelBtn, SIGNAL(clicked()), this, SLOT(addNewChannel()));
ml->addWidget(newChannelBtn, 0, Qt::AlignTop);
// add the stacked layout for the effect racks of mixer channels
ml->addWidget( m_racksWidget, 0, Qt::AlignTop | Qt::AlignRight );
m_racksWidget->setFixedHeight(mixerChannelSize.height());
ml->addWidget(m_racksWidget);
setCurrentMixerLine( m_mixerChannelViews[0]->m_mixerLine );
setCurrentMixerChannel(m_mixerChannelViews[0]);
setLayout( ml );
updateGeometry();
// timer for updating faders
connect( getGUI()->mainWindow(), SIGNAL(periodicUpdate()),
this, SLOT(updateFaders()));
auto* mainWindow = getGUI()->mainWindow();
// timer for updating faders
connect(mainWindow, &MainWindow::periodicUpdate, this, &MixerView::updateFaders);
// add ourself to workspace
QMdiSubWindow * subWin = getGUI()->mainWindow()->addWindowedWidget( this );
QMdiSubWindow* subWin = mainWindow->addWindowedWidget(this);
Qt::WindowFlags flags = subWin->windowFlags();
flags &= ~Qt::WindowMaximizeButtonHint;
subWin->setWindowFlags( flags );
layout()->setSizeConstraint( QLayout::SetMinimumSize );
subWin->layout()->setSizeConstraint( QLayout::SetMinAndMaxSize );
subWin->setWindowFlags(flags);
layout()->setSizeConstraint(QLayout::SetMinimumSize);
subWin->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false );
parentWidget()->move( 5, 310 );
parentWidget()->setAttribute(Qt::WA_DeleteOnClose, false);
parentWidget()->move(5, 310);
// we want to receive dataChanged-signals in order to update
setModel( m );
setModel(m);
}
MixerView::~MixerView()
{
for (auto mixerChannelView : m_mixerChannelViews)
{
delete mixerChannelView;
}
}
@@ -194,12 +189,11 @@ int MixerView::addNewChannel()
Mixer * mix = Engine::mixer();
int newChannelIndex = mix->createChannel();
m_mixerChannelViews.push_back(new MixerChannelView(m_channelAreaWidget, this,
newChannelIndex));
chLayout->addWidget( m_mixerChannelViews[newChannelIndex]->m_mixerLine );
m_racksLayout->addWidget( m_mixerChannelViews[newChannelIndex]->m_rackView );
m_mixerChannelViews.push_back(new MixerChannelView(m_channelAreaWidget, this, newChannelIndex));
chLayout->addWidget(m_mixerChannelViews[newChannelIndex]);
m_racksLayout->addWidget(m_mixerChannelViews[newChannelIndex]->m_effectRackView);
updateMixerLine(newChannelIndex);
updateMixerChannel(newChannelIndex);
updateMaxChannelSelector();
@@ -210,35 +204,29 @@ int MixerView::addNewChannel()
void MixerView::refreshDisplay()
{
// delete all views and re-add them
for( int i = 1; i<m_mixerChannelViews.size(); ++i )
for (int i = 1; i<m_mixerChannelViews.size(); ++i)
{
chLayout->removeWidget(m_mixerChannelViews[i]->m_mixerLine);
m_racksLayout->removeWidget( m_mixerChannelViews[i]->m_rackView );
delete m_mixerChannelViews[i]->m_fader;
delete m_mixerChannelViews[i]->m_muteBtn;
delete m_mixerChannelViews[i]->m_soloBtn;
delete m_mixerChannelViews[i]->m_mixerLine;
delete m_mixerChannelViews[i]->m_rackView;
delete m_mixerChannelViews[i];
chLayout->removeWidget(m_mixerChannelViews[i]);
m_racksLayout->removeWidget(m_mixerChannelViews[i]->m_effectRackView);
}
m_channelAreaWidget->adjustSize();
// re-add the views
m_mixerChannelViews.resize(Engine::mixer()->numChannels());
for( int i = 1; i < m_mixerChannelViews.size(); ++i )
for (int i = 1; i < m_mixerChannelViews.size(); ++i)
{
m_mixerChannelViews[i] = new MixerChannelView(m_channelAreaWidget, this, i);
chLayout->addWidget(m_mixerChannelViews[i]->m_mixerLine);
m_racksLayout->addWidget( m_mixerChannelViews[i]->m_rackView );
chLayout->addWidget(m_mixerChannelViews[i]);
m_racksLayout->addWidget(m_mixerChannelViews[i]->m_effectRackView);
}
// set selected mixer line to 0
setCurrentMixerLine( 0 );
// set selected mixer channel to 0
setCurrentMixerChannel(0);
// update all mixer lines
for( int i = 0; i < m_mixerChannelViews.size(); ++i )
for (int i = 0; i < m_mixerChannelViews.size(); ++i)
{
updateMixerLine( i );
updateMixerChannel(i);
}
updateMaxChannelSelector();
@@ -272,74 +260,21 @@ void MixerView::updateMaxChannelSelector()
}
void MixerView::saveSettings( QDomDocument & _doc, QDomElement & _this )
void MixerView::saveSettings(QDomDocument& doc, QDomElement& domElement)
{
MainWindow::saveWidgetState( this, _this );
MainWindow::saveWidgetState(this, domElement);
}
void MixerView::loadSettings( const QDomElement & _this )
void MixerView::loadSettings(const QDomElement& domElement)
{
MainWindow::restoreWidgetState( this, _this );
MainWindow::restoreWidgetState(this, domElement);
}
MixerView::MixerChannelView::MixerChannelView(QWidget * _parent, MixerView * _mv,
int channelIndex )
{
m_mixerLine = new MixerLine(_parent, _mv, channelIndex);
MixerChannel *mixerChannel = Engine::mixer()->mixerChannel(channelIndex);
m_fader = new Fader( &mixerChannel->m_volumeModel,
tr( "Fader %1" ).arg( channelIndex ), m_mixerLine );
m_fader->setLevelsDisplayedInDBFS();
m_fader->setMinPeak(dbfsToAmp(-42));
m_fader->setMaxPeak(dbfsToAmp(9));
m_fader->move( 16-m_fader->width()/2,
m_mixerLine->height()-
m_fader->height()-5 );
m_muteBtn = new PixmapButton( m_mixerLine, tr( "Mute" ) );
m_muteBtn->setModel( &mixerChannel->m_muteModel );
m_muteBtn->setActiveGraphic(
embed::getIconPixmap( "led_off" ) );
m_muteBtn->setInactiveGraphic(
embed::getIconPixmap( "led_green" ) );
m_muteBtn->setCheckable( true );
m_muteBtn->move( 9, m_fader->y()-11);
m_muteBtn->setToolTip(tr("Mute this channel"));
m_soloBtn = new PixmapButton( m_mixerLine, tr( "Solo" ) );
m_soloBtn->setModel( &mixerChannel->m_soloModel );
m_soloBtn->setActiveGraphic(
embed::getIconPixmap( "led_red" ) );
m_soloBtn->setInactiveGraphic(
embed::getIconPixmap( "led_off" ) );
m_soloBtn->setCheckable( true );
m_soloBtn->move( 9, m_fader->y()-21);
connect(&mixerChannel->m_soloModel, SIGNAL(dataChanged()),
_mv, SLOT ( toggledSolo() ), Qt::DirectConnection );
m_soloBtn->setToolTip(tr("Solo this channel"));
// Create EffectRack for the channel
m_rackView = new EffectRackView( &mixerChannel->m_fxChain, _mv->m_racksWidget );
m_rackView->setFixedSize( EffectRackView::DEFAULT_WIDTH, MixerLine::MixerLineHeight );
}
void MixerView::MixerChannelView::setChannelIndex( int index )
{
MixerChannel* mixerChannel = Engine::mixer()->mixerChannel( index );
m_fader->setModel( &mixerChannel->m_volumeModel );
m_muteBtn->setModel( &mixerChannel->m_muteModel );
m_soloBtn->setModel( &mixerChannel->m_soloModel );
m_rackView->setModel( &mixerChannel->m_fxChain );
}
void MixerView::toggledSolo()
@@ -349,31 +284,31 @@ void MixerView::toggledSolo()
void MixerView::setCurrentMixerLine( MixerLine * _line )
void MixerView::setCurrentMixerChannel(MixerChannelView* channel)
{
// select
m_currentMixerLine = _line;
m_racksLayout->setCurrentWidget( m_mixerChannelViews[ _line->channelIndex() ]->m_rackView );
m_currentMixerChannel = channel;
m_racksLayout->setCurrentWidget(m_mixerChannelViews[channel->channelIndex()]->m_effectRackView);
// set up send knob
for(int i = 0; i < m_mixerChannelViews.size(); ++i)
for (int i = 0; i < m_mixerChannelViews.size(); ++i)
{
updateMixerLine(i);
updateMixerChannel(i);
}
}
void MixerView::updateMixerLine(int index)
void MixerView::updateMixerChannel(int index)
{
Mixer * mix = Engine::mixer();
// does current channel send to this channel?
int selIndex = m_currentMixerLine->channelIndex();
MixerLine * thisLine = m_mixerChannelViews[index]->m_mixerLine;
thisLine->setToolTip( Engine::mixer()->mixerChannel( index )->m_name );
int selIndex = m_currentMixerChannel->channelIndex();
auto thisLine = m_mixerChannelViews[index];
thisLine->setToolTip(Engine::mixer()->mixerChannel(index)->m_name);
FloatModel * sendModel = mix->channelSendModel(selIndex, index);
if( sendModel == nullptr )
if (sendModel == nullptr)
{
// does not send, hide send knob
thisLine->m_sendKnob->setVisible(false);
@@ -386,8 +321,8 @@ void MixerView::updateMixerLine(int index)
}
// disable the send button if it would cause an infinite loop
thisLine->m_sendBtn->setVisible(! mix->isInfiniteLoop(selIndex, index));
thisLine->m_sendBtn->updateLightStatus();
thisLine->m_sendButton->setVisible(!mix->isInfiniteLoop(selIndex, index));
thisLine->m_sendButton->updateLightStatus();
thisLine->update();
}
@@ -395,7 +330,7 @@ void MixerView::updateMixerLine(int index)
void MixerView::deleteChannel(int index)
{
// can't delete master
if( index == 0 ) return;
if (index == 0) return;
// if there is no user confirmation, do nothing
if (!confirmRemoval(index))
@@ -404,7 +339,7 @@ void MixerView::deleteChannel(int index)
}
// remember selected line
int selLine = m_currentMixerLine->channelIndex();
int selLine = m_currentMixerChannel->channelIndex();
// in case the deleted channel is soloed or the remaining
// channels will be left in a muted state
@@ -413,23 +348,17 @@ void MixerView::deleteChannel(int index)
// delete the real channel
Engine::mixer()->deleteChannel(index);
// delete the view
chLayout->removeWidget(m_mixerChannelViews[index]->m_mixerLine);
m_racksLayout->removeWidget(m_mixerChannelViews[index]->m_rackView);
delete m_mixerChannelViews[index]->m_fader;
delete m_mixerChannelViews[index]->m_muteBtn;
delete m_mixerChannelViews[index]->m_soloBtn;
// delete mixerLine later to prevent a crash when deleting from context menu
m_mixerChannelViews[index]->m_mixerLine->hide();
m_mixerChannelViews[index]->m_mixerLine->deleteLater();
delete m_mixerChannelViews[index]->m_rackView;
delete m_mixerChannelViews[index];
chLayout->removeWidget(m_mixerChannelViews[index]);
m_racksLayout->removeWidget(m_mixerChannelViews[index]);
// delete MixerChannelView later to prevent a crash when deleting from context menu
m_mixerChannelViews[index]->hide();
m_mixerChannelViews[index]->deleteLater();
m_channelAreaWidget->adjustSize();
// make sure every channel knows what index it is
for (int i = index + 1; i < m_mixerChannelViews.size(); ++i)
{
m_mixerChannelViews[i]->m_mixerLine->setChannelIndex(i - 1);
m_mixerChannelViews[i]->setChannelIndex(i - 1);
}
m_mixerChannelViews.remove(index);
@@ -438,7 +367,7 @@ void MixerView::deleteChannel(int index)
{
selLine = m_mixerChannelViews.size() - 1;
}
setCurrentMixerLine(selLine);
setCurrentMixerChannel(selLine);
updateMaxChannelSelector();
}
@@ -503,39 +432,39 @@ void MixerView::deleteUnusedChannels()
void MixerView::moveChannelLeft(int index, int focusIndex)
{
// can't move master or first channel left or last channel right
if( index <= 1 || index >= m_mixerChannelViews.size() ) return;
if (index <= 1 || index >= m_mixerChannelViews.size()) return;
Mixer *m = Engine::mixer();
// Move instruments channels
m->moveChannelLeft( index );
m->moveChannelLeft(index);
// Update widgets models
m_mixerChannelViews[index]->setChannelIndex( index );
m_mixerChannelViews[index - 1]->setChannelIndex( index - 1 );
m_mixerChannelViews[index]->setChannelIndex(index);
m_mixerChannelViews[index - 1]->setChannelIndex(index - 1);
// Focus on new position
setCurrentMixerLine( focusIndex );
setCurrentMixerChannel(focusIndex);
}
void MixerView::moveChannelLeft(int index)
{
moveChannelLeft( index, index - 1 );
moveChannelLeft(index, index - 1);
}
void MixerView::moveChannelRight(int index)
{
moveChannelLeft( index + 1, index + 1 );
moveChannelLeft(index + 1, index + 1);
}
void MixerView::renameChannel(int index)
{
m_mixerChannelViews[index]->m_mixerLine->renameChannel();
m_mixerChannelViews[index]->renameChannel();
}
@@ -545,32 +474,32 @@ void MixerView::keyPressEvent(QKeyEvent * e)
switch(e->key())
{
case Qt::Key_Delete:
deleteChannel(m_currentMixerLine->channelIndex());
deleteChannel(m_currentMixerChannel->channelIndex());
break;
case Qt::Key_Left:
if( e->modifiers() & Qt::AltModifier )
if (e->modifiers() & Qt::AltModifier)
{
moveChannelLeft( m_currentMixerLine->channelIndex() );
moveChannelLeft(m_currentMixerChannel->channelIndex());
}
else
{
// select channel to the left
setCurrentMixerLine( m_currentMixerLine->channelIndex()-1 );
setCurrentMixerChannel(m_currentMixerChannel->channelIndex() - 1);
}
break;
case Qt::Key_Right:
if( e->modifiers() & Qt::AltModifier )
if (e->modifiers() & Qt::AltModifier)
{
moveChannelRight( m_currentMixerLine->channelIndex() );
moveChannelRight(m_currentMixerChannel->channelIndex());
}
else
{
// select channel to the right
setCurrentMixerLine( m_currentMixerLine->channelIndex()+1 );
setCurrentMixerChannel(m_currentMixerChannel->channelIndex() + 1);
}
break;
case Qt::Key_Insert:
if ( e->modifiers() & Qt::ShiftModifier )
if (e->modifiers() & Qt::ShiftModifier)
{
addNewChannel();
}
@@ -578,16 +507,16 @@ void MixerView::keyPressEvent(QKeyEvent * e)
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_F2:
renameChannel( m_currentMixerLine->channelIndex() );
renameChannel(m_currentMixerChannel->channelIndex());
break;
}
}
void MixerView::closeEvent( QCloseEvent * _ce )
void MixerView::closeEvent(QCloseEvent * ce)
{
if( parentWidget() )
if (parentWidget())
{
parentWidget()->hide();
}
@@ -595,16 +524,16 @@ void MixerView::closeEvent( QCloseEvent * _ce )
{
hide();
}
_ce->ignore();
ce->ignore();
}
void MixerView::setCurrentMixerLine( int _line )
void MixerView::setCurrentMixerChannel(int channel)
{
if( _line >= 0 && _line < m_mixerChannelViews.size() )
if (channel >= 0 && channel < m_mixerChannelViews.size())
{
setCurrentMixerLine( m_mixerChannelViews[_line]->m_mixerLine );
setCurrentMixerChannel(m_mixerChannelViews[channel]);
}
}
@@ -628,31 +557,31 @@ void MixerView::updateFaders()
m->mixerChannel(0)->m_peakLeft *= Engine::audioEngine()->masterGain();
m->mixerChannel(0)->m_peakRight *= Engine::audioEngine()->masterGain();
for( int i = 0; i < m_mixerChannelViews.size(); ++i )
for (int i = 0; i < m_mixerChannelViews.size(); ++i)
{
const float opl = m_mixerChannelViews[i]->m_fader->getPeak_L();
const float opr = m_mixerChannelViews[i]->m_fader->getPeak_R();
const float fallOff = 1.25;
if( m->mixerChannel(i)->m_peakLeft >= opl/fallOff )
if (m->mixerChannel(i)->m_peakLeft >= opl/fallOff)
{
m_mixerChannelViews[i]->m_fader->setPeak_L( m->mixerChannel(i)->m_peakLeft );
m_mixerChannelViews[i]->m_fader->setPeak_L(m->mixerChannel(i)->m_peakLeft);
// Set to -1 so later we'll know if this value has been refreshed yet.
m->mixerChannel(i)->m_peakLeft = -1;
}
else if( m->mixerChannel(i)->m_peakLeft != -1 )
else if (m->mixerChannel(i)->m_peakLeft != -1)
{
m_mixerChannelViews[i]->m_fader->setPeak_L( opl/fallOff );
m_mixerChannelViews[i]->m_fader->setPeak_L(opl/fallOff);
}
if( m->mixerChannel(i)->m_peakRight >= opr/fallOff )
if (m->mixerChannel(i)->m_peakRight >= opr/fallOff)
{
m_mixerChannelViews[i]->m_fader->setPeak_R( m->mixerChannel(i)->m_peakRight );
m_mixerChannelViews[i]->m_fader->setPeak_R(m->mixerChannel(i)->m_peakRight);
// Set to -1 so later we'll know if this value has been refreshed yet.
m->mixerChannel(i)->m_peakRight = -1;
}
else if( m->mixerChannel(i)->m_peakRight != -1 )
else if (m->mixerChannel(i)->m_peakRight != -1)
{
m_mixerChannelViews[i]->m_fader->setPeak_R( opr/fallOff );
m_mixerChannelViews[i]->m_fader->setPeak_R(opr/fallOff);
}
}
}

View File

@@ -21,7 +21,7 @@
* Boston, MA 02110-1301 USA.
*
*/
#include "SampleTrackWindow.h"
#include <QCloseEvent>
@@ -37,7 +37,7 @@
#include "GuiApplication.h"
#include "Knob.h"
#include "MainWindow.h"
#include "MixerLineLcdSpinBox.h"
#include "MixerChannelLcdSpinBox.h"
#include "SampleTrackView.h"
#include "Song.h"
#include "SubWindow.h"
@@ -133,7 +133,7 @@ SampleTrackWindow::SampleTrackWindow(SampleTrackView * tv) :
// setup spinbox for selecting Mixer-channel
m_mixerChannelNumber = new MixerLineLcdSpinBox(2, nullptr, tr("Mixer channel"), m_stv);
m_mixerChannelNumber = new MixerChannelLcdSpinBox(2, nullptr, tr("Mixer channel"), m_stv);
basicControlsLayout->addWidget(m_mixerChannelNumber, 0, 3);
basicControlsLayout->setAlignment(m_mixerChannelNumber, widgetAlignment);

View File

@@ -2,51 +2,48 @@
#include "embed.h"
#include "Mixer.h"
#include "MixerLine.h"
#include "MixerChannelView.h"
#include "MixerView.h"
namespace lmms::gui
{
SendButtonIndicator:: SendButtonIndicator( QWidget * _parent, MixerLine * _owner,
MixerView * _mv) :
QLabel( _parent ),
m_parent( _owner ),
m_mv( _mv )
SendButtonIndicator:: SendButtonIndicator(QWidget* parent, MixerChannelView* owner, MixerView* mv) :
QLabel(parent),
m_parent(owner),
m_mv(mv)
{
// don't do any initializing yet, because the MixerView and MixerLine
// don't do any initializing yet, because the MixerView and MixerChannelView
// that were passed to this constructor are not done with their constructors
// yet.
setPixmap(m_qpmOff);
}
void SendButtonIndicator::mousePressEvent( QMouseEvent * e )
void SendButtonIndicator::mousePressEvent(QMouseEvent* e)
{
Mixer * mix = Engine::mixer();
int from = m_mv->currentMixerLine()->channelIndex();
Mixer* mix = Engine::mixer();
int from = m_mv->currentMixerChannel()->channelIndex();
int to = m_parent->channelIndex();
FloatModel * sendModel = mix->channelSendModel(from, to);
if( sendModel == nullptr )
FloatModel* sendModel = mix->channelSendModel(from, to);
if (sendModel == nullptr)
{
// not sending. create a mixer send.
mix->createChannelSend( from, to );
mix->createChannelSend(from, to);
}
else
{
// sending. delete the mixer send.
mix->deleteChannelSend( from, to );
mix->deleteChannelSend(from, to);
}
m_mv->updateMixerLine(m_parent->channelIndex());
m_mv->updateMixerChannel(m_parent->channelIndex());
updateLightStatus();
}
FloatModel * SendButtonIndicator::getSendModel()
FloatModel* SendButtonIndicator::getSendModel()
{
Mixer * mix = Engine::mixer();
return mix->channelSendModel(
m_mv->currentMixerLine()->channelIndex(), m_parent->channelIndex());
Mixer* mix = Engine::mixer();
return mix->channelSendModel(m_mv->currentMixerChannel()->channelIndex(), m_parent->channelIndex());
}
void SendButtonIndicator::updateLightStatus()

View File

@@ -42,7 +42,7 @@
#include "FileBrowser.h"
#include "FileDialog.h"
#include "GroupBox.h"
#include "MixerLineLcdSpinBox.h"
#include "MixerChannelLcdSpinBox.h"
#include "GuiApplication.h"
#include "gui_templates.h"
#include "Instrument.h"
@@ -206,7 +206,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
// setup spinbox for selecting Mixer-channel
m_mixerChannelNumber = new MixerLineLcdSpinBox( 2, nullptr, tr( "Mixer channel" ), m_itv );
m_mixerChannelNumber = new MixerChannelLcdSpinBox(2, nullptr, tr("Mixer channel"), m_itv);
basicControlsLayout->addWidget( m_mixerChannelNumber, 0, 6 );
basicControlsLayout->setAlignment( m_mixerChannelNumber, widgetAlignment );

View File

@@ -74,7 +74,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV
connect(ConfigManager::inst(), SIGNAL(valueChanged(QString,QString,QString)),
this, SLOT(handleConfigChange(QString,QString,QString)));
m_mixerChannelNumber = new MixerLineLcdSpinBox(2, getTrackSettingsWidget(), tr("Mixer channel"), this);
m_mixerChannelNumber = new MixerChannelLcdSpinBox(2, getTrackSettingsWidget(), tr("Mixer channel"), this);
m_mixerChannelNumber->show();
m_volumeKnob = new Knob( KnobType::Small17, getTrackSettingsWidget(),
@@ -240,7 +240,7 @@ void InstrumentTrackView::assignMixerLine(int channelIndex)
{
model()->mixerChannelModel()->setValue( channelIndex );
getGUI()->mixerView()->setCurrentMixerLine( channelIndex );
getGUI()->mixerView()->setCurrentMixerChannel(channelIndex);
}

View File

@@ -21,7 +21,7 @@
* Boston, MA 02110-1301 USA.
*
*/
#include "SampleTrackView.h"
#include <QApplication>
@@ -58,7 +58,7 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) :
m_tlb->setIcon(embed::getIconPixmap("sample_track"));
m_tlb->show();
m_mixerChannelNumber = new MixerLineLcdSpinBox(2, getTrackSettingsWidget(), tr("Mixer channel"), this);
m_mixerChannelNumber = new MixerChannelLcdSpinBox(2, getTrackSettingsWidget(), tr("Mixer channel"), this);
m_mixerChannelNumber->show();
m_volumeKnob = new Knob( KnobType::Small17, getTrackSettingsWidget(),
@@ -241,7 +241,7 @@ void SampleTrackView::assignMixerLine(int channelIndex)
{
model()->mixerChannelModel()->setValue(channelIndex);
getGUI()->mixerView()->setCurrentMixerLine(channelIndex);
getGUI()->mixerView()->setCurrentMixerChannel(channelIndex);
}

View File

@@ -1,5 +1,5 @@
/*
* MixerLineLcdSpinBox.cpp - a specialization of LcdSpnBox for setting mixer channels
* MixerChannelLcdSpinBox.cpp - a specialization of LcdSpnBox for setting mixer channels
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -22,7 +22,7 @@
*
*/
#include "MixerLineLcdSpinBox.h"
#include "MixerChannelLcdSpinBox.h"
#include "CaptionMenu.h"
#include "MixerView.h"
@@ -33,14 +33,14 @@ namespace lmms::gui
{
void MixerLineLcdSpinBox::setTrackView(TrackView * tv)
void MixerChannelLcdSpinBox::setTrackView(TrackView * tv)
{
m_tv = tv;
}
void MixerLineLcdSpinBox::mouseDoubleClickEvent(QMouseEvent* event)
void MixerChannelLcdSpinBox::mouseDoubleClickEvent(QMouseEvent* event)
{
getGUI()->mixerView()->setCurrentMixerLine(model()->value());
getGUI()->mixerView()->setCurrentMixerChannel(model()->value());
getGUI()->mixerView()->parentWidget()->show();
getGUI()->mixerView()->show();// show Mixer window
@@ -48,7 +48,7 @@ void MixerLineLcdSpinBox::mouseDoubleClickEvent(QMouseEvent* event)
//engine::getMixerView()->raise();
}
void MixerLineLcdSpinBox::contextMenuEvent(QContextMenuEvent* event)
void MixerChannelLcdSpinBox::contextMenuEvent(QContextMenuEvent* event)
{
// for the case, the user clicked right while pressing left mouse-
// button, the context-menu appears while mouse-cursor is still hidden